| 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'; |
| 11 import 'package:analyzer/src/dart/scanner/reader.dart'; | 11 import 'package:analyzer/src/dart/scanner/reader.dart'; |
| 12 import 'package:analyzer/src/dart/scanner/scanner.dart'; | 12 import 'package:analyzer/src/dart/scanner/scanner.dart'; |
| 13 import 'package:analyzer/src/dart/sdk/sdk.dart'; | 13 import 'package:analyzer/src/dart/sdk/sdk.dart'; |
| 14 import 'package:analyzer/src/generated/parser.dart'; | 14 import 'package:analyzer/src/generated/parser.dart'; |
| 15 import 'package:analyzer/src/generated/sdk.dart'; | 15 import 'package:analyzer/src/generated/sdk.dart'; |
| 16 import 'package:analyzer/src/generated/source.dart'; | 16 import 'package:analyzer/src/generated/source.dart'; |
| 17 import 'package:meta/meta.dart'; | 17 import 'package:meta/meta.dart'; |
| 18 import 'package:path/src/context.dart'; | 18 import 'package:path/src/context.dart'; |
| 19 | 19 |
| 20 /** | 20 /** |
| 21 * [SdkPatcher] applies patches to SDK [CompilationUnit]. | 21 * [SdkPatcher] applies patches to SDK [CompilationUnit]. |
| 22 */ | 22 */ |
| 23 class SdkPatcher { | 23 class SdkPatcher { |
| 24 bool _allowNewPublicNames; |
| 24 String _baseDesc; | 25 String _baseDesc; |
| 25 String _patchDesc; | 26 String _patchDesc; |
| 26 CompilationUnit _patchUnit; | 27 CompilationUnit _patchUnit; |
| 27 | 28 |
| 28 /** | 29 /** |
| 29 * Patch the given [unit] of a SDK [source] with the patches defined in | 30 * Patch the given [unit] of a SDK [source] with the patches defined in |
| 30 * the [sdk] for the given [platform]. Throw [ArgumentError] if a patch | 31 * the [sdk] for the given [platform]. Throw [ArgumentError] if a patch |
| 31 * file cannot be read, or the contents violates rules for patch files. | 32 * file cannot be read, or the contents violates rules for patch files. |
| 32 */ | 33 */ |
| 33 void patch( | 34 void patch( |
| 34 FolderBasedDartSdk sdk, | 35 FolderBasedDartSdk sdk, |
| 35 int platform, | 36 int platform, |
| 36 AnalysisErrorListener errorListener, | 37 AnalysisErrorListener errorListener, |
| 37 Source source, | 38 Source source, |
| 38 CompilationUnit unit) { | 39 CompilationUnit unit) { |
| 39 // Process URI. | 40 // Process URI. |
| 40 String libraryUriStr; | 41 String libraryUriStr; |
| 41 bool isLibraryDefiningUnit; | 42 bool isLibraryDefiningUnit; |
| 42 { | 43 { |
| 43 Uri uri = source.uri; | 44 Uri uri = source.uri; |
| 44 if (uri.scheme != 'dart') { | 45 if (uri.scheme != 'dart') { |
| 45 throw new ArgumentError( | 46 throw new ArgumentError( |
| 46 'The URI of the unit to patch must have the "dart" scheme: $uri'); | 47 'The URI of the unit to patch must have the "dart" scheme: $uri'); |
| 47 } | 48 } |
| 48 List<String> uriSegments = uri.pathSegments; | 49 List<String> uriSegments = uri.pathSegments; |
| 49 libraryUriStr = 'dart:${uriSegments.first}'; | 50 String libraryName = uriSegments.first; |
| 51 libraryUriStr = 'dart:$libraryName'; |
| 50 isLibraryDefiningUnit = uriSegments.length == 1; | 52 isLibraryDefiningUnit = uriSegments.length == 1; |
| 53 _allowNewPublicNames = libraryName == '_internal'; |
| 51 } | 54 } |
| 52 // Prepare the patch files to apply. | 55 // Prepare the patch files to apply. |
| 53 List<String> patchPaths; | 56 List<String> patchPaths; |
| 54 { | 57 { |
| 55 SdkLibrary sdkLibrary = sdk.getSdkLibrary(libraryUriStr); | 58 SdkLibrary sdkLibrary = sdk.getSdkLibrary(libraryUriStr); |
| 56 if (sdkLibrary == null) { | 59 if (sdkLibrary == null) { |
| 57 throw new ArgumentError( | 60 throw new ArgumentError( |
| 58 'The library $libraryUriStr is not defined in the SDK.'); | 61 'The library $libraryUriStr is not defined in the SDK.'); |
| 59 } | 62 } |
| 60 patchPaths = sdkLibrary.getPatches(platform); | 63 patchPaths = sdkLibrary.getPatches(platform); |
| (...skipping 22 matching lines...) Expand all Loading... |
| 83 _patchTopLevelDeclarations(unit, patchUnit, isLibraryDefiningUnit); | 86 _patchTopLevelDeclarations(unit, patchUnit, isLibraryDefiningUnit); |
| 84 } | 87 } |
| 85 } | 88 } |
| 86 | 89 |
| 87 void _failExternalKeyword(String name, int offset) { | 90 void _failExternalKeyword(String name, int offset) { |
| 88 throw new ArgumentError( | 91 throw new ArgumentError( |
| 89 'The keyword "external" was expected for "$name" in $_baseDesc @ $offset
.'); | 92 'The keyword "external" was expected for "$name" in $_baseDesc @ $offset
.'); |
| 90 } | 93 } |
| 91 | 94 |
| 92 void _failIfPublicName(AstNode node, String name) { | 95 void _failIfPublicName(AstNode node, String name) { |
| 96 if (_allowNewPublicNames) { |
| 97 return; |
| 98 } |
| 93 if (!Identifier.isPrivateName(name)) { | 99 if (!Identifier.isPrivateName(name)) { |
| 94 _failInPatch('contains a public declaration "$name"', node.offset); | 100 _failInPatch('contains a public declaration "$name"', node.offset); |
| 95 } | 101 } |
| 96 } | 102 } |
| 97 | 103 |
| 98 void _failInPatch(String message, int offset) { | 104 void _failInPatch(String message, int offset) { |
| 99 String loc = _getLocationDesc3(_patchUnit, offset); | 105 String loc = _getLocationDesc3(_patchUnit, offset); |
| 100 throw new ArgumentError( | 106 throw new ArgumentError( |
| 101 'The patch file $_patchDesc for $_baseDesc $message at $loc.'); | 107 'The patch file $_patchDesc for $_baseDesc $message at $loc.'); |
| 102 } | 108 } |
| (...skipping 11 matching lines...) Expand all Loading... |
| 114 if (patchMember is FieldDeclaration) { | 120 if (patchMember is FieldDeclaration) { |
| 115 if (_hasPatchAnnotation(patchMember.metadata)) { | 121 if (_hasPatchAnnotation(patchMember.metadata)) { |
| 116 _failInPatch('attempts to patch a field', patchMember.offset); | 122 _failInPatch('attempts to patch a field', patchMember.offset); |
| 117 } | 123 } |
| 118 List<VariableDeclaration> fields = patchMember.fields.variables; | 124 List<VariableDeclaration> fields = patchMember.fields.variables; |
| 119 if (fields.length != 1) { | 125 if (fields.length != 1) { |
| 120 _failInPatch('contains a field declaration with more than one field', | 126 _failInPatch('contains a field declaration with more than one field', |
| 121 patchMember.offset); | 127 patchMember.offset); |
| 122 } | 128 } |
| 123 String name = fields[0].name.name; | 129 String name = fields[0].name.name; |
| 124 if (!Identifier.isPrivateName(className) && | 130 if (!_allowNewPublicNames && |
| 131 !Identifier.isPrivateName(className) && |
| 125 !Identifier.isPrivateName(name)) { | 132 !Identifier.isPrivateName(name)) { |
| 126 // TODO(scheglov) allow adding public fields into dart:_internal | |
| 127 _failInPatch('contains a public field', patchMember.offset); | 133 _failInPatch('contains a public field', patchMember.offset); |
| 128 } | 134 } |
| 129 membersToAppend.add(patchMember); | 135 membersToAppend.add(patchMember); |
| 130 } else if (patchMember is MethodDeclaration) { | 136 } else if (patchMember is MethodDeclaration) { |
| 131 String name = patchMember.name.name; | 137 String name = patchMember.name.name; |
| 132 if (_hasPatchAnnotation(patchMember.metadata)) { | 138 if (_hasPatchAnnotation(patchMember.metadata)) { |
| 133 for (ClassMember baseMember in baseClass.members) { | 139 for (ClassMember baseMember in baseClass.members) { |
| 134 if (baseMember is MethodDeclaration && | 140 if (baseMember is MethodDeclaration && |
| 135 baseMember.name.name == name) { | 141 baseMember.name.name == name) { |
| 136 // Remove the "external" keyword. | 142 // Remove the "external" keyword. |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 199 patchBody.endToken.setNext(baseBody.endToken.next); | 205 patchBody.endToken.setNext(baseBody.endToken.next); |
| 200 } else { | 206 } else { |
| 201 _replaceNodeTokens(baseBody, patchBody); | 207 _replaceNodeTokens(baseBody, patchBody); |
| 202 } | 208 } |
| 203 // Replace the body. | 209 // Replace the body. |
| 204 baseMember.body = patchBody; | 210 baseMember.body = patchBody; |
| 205 } | 211 } |
| 206 } | 212 } |
| 207 } else { | 213 } else { |
| 208 if (name == null) { | 214 if (name == null) { |
| 209 if (!Identifier.isPrivateName(className)) { | 215 if (!_allowNewPublicNames && !Identifier.isPrivateName(className)) { |
| 210 _failInPatch( | 216 _failInPatch( |
| 211 'contains an unnamed public constructor', patchMember.offset); | 217 'contains an unnamed public constructor', patchMember.offset); |
| 212 } | 218 } |
| 213 } else { | 219 } else { |
| 214 _failIfPublicName(patchMember, name); | 220 _failIfPublicName(patchMember, name); |
| 215 } | 221 } |
| 216 membersToAppend.add(patchMember); | 222 membersToAppend.add(patchMember); |
| 217 } | 223 } |
| 218 } else { | 224 } else { |
| 219 String className = patchClass.name.name; | 225 String className = patchClass.name.name; |
| (...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 356 } | 362 } |
| 357 | 363 |
| 358 /** | 364 /** |
| 359 * Replace tokens of the [oldNode] with tokens of the [newNode]. | 365 * Replace tokens of the [oldNode] with tokens of the [newNode]. |
| 360 */ | 366 */ |
| 361 static void _replaceNodeTokens(AstNode oldNode, AstNode newNode) { | 367 static void _replaceNodeTokens(AstNode oldNode, AstNode newNode) { |
| 362 oldNode.beginToken.previous.setNext(newNode.beginToken); | 368 oldNode.beginToken.previous.setNext(newNode.beginToken); |
| 363 newNode.endToken.setNext(oldNode.endToken.next); | 369 newNode.endToken.setNext(oldNode.endToken.next); |
| 364 } | 370 } |
| 365 } | 371 } |
| OLD | NEW |