Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(271)

Side by Side Diff: pkg/analyzer/lib/src/dart/sdk/patch.dart

Issue 2414123003: Add support for patching parts. (Closed)
Patch Set: Created 4 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | pkg/analyzer/test/src/dart/sdk/patch_test.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 11 matching lines...) Expand all
22 */ 22 */
23 class SdkPatcher { 23 class SdkPatcher {
24 String _baseDesc; 24 String _baseDesc;
25 String _patchDesc; 25 String _patchDesc;
26 CompilationUnit _patchUnit; 26 CompilationUnit _patchUnit;
27 27
28 /** 28 /**
29 * Patch the given [unit] of a SDK [source] with the patches defined in 29 * 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 30 * the [sdk] for the given [platform]. Throw [ArgumentError] if a patch
31 * file cannot be read, or the contents violates rules for patch files. 31 * file cannot be read, or the contents violates rules for patch files.
32 *
33 * If [addNewTopLevelDeclarations] is `true`, then the [unit] is the
34 * defining unit of a library, so new top-level declarations should be
35 * added to this unit. For parts new declarations may be added only to the
36 * patched classes.
37 *
38 * TODO(scheglov) auto-detect [addNewTopLevelDeclarations]
39 */ 32 */
40 void patch(FolderBasedDartSdk sdk, int platform, 33 void patch(
41 AnalysisErrorListener errorListener, Source source, CompilationUnit unit, 34 FolderBasedDartSdk sdk,
42 {bool addNewTopLevelDeclarations: true}) { 35 int platform,
36 AnalysisErrorListener errorListener,
37 Source source,
38 CompilationUnit unit) {
39 // Process URI.
40 String libraryUriStr;
41 bool isLibraryDefiningUnit;
42 {
43 Uri uri = source.uri;
44 if (uri.scheme != 'dart') {
45 throw new ArgumentError(
46 'The URI of the unit to patch must has the "dart" scheme: $uri');
Brian Wilkerson 2016/10/13 21:05:31 "has" --> "have"
47 }
48 List<String> uriSegments = uri.pathSegments;
49 libraryUriStr = 'dart:${uriSegments.first}';
50 isLibraryDefiningUnit = uriSegments.length == 1;
51 }
43 // Prepare the patch files to apply. 52 // Prepare the patch files to apply.
44 List<String> patchPaths; 53 List<String> patchPaths;
45 { 54 {
46 // TODO(scheglov) add support for patching parts 55 SdkLibrary sdkLibrary = sdk.getSdkLibrary(libraryUriStr);
47 String uriStr = source.uri.toString();
48 SdkLibrary sdkLibrary = sdk.getSdkLibrary(uriStr);
49 if (sdkLibrary == null) { 56 if (sdkLibrary == null) {
50 throw new ArgumentError( 57 throw new ArgumentError(
51 'The library $uriStr is not defined in the SDK.'); 58 'The library $libraryUriStr is not defined in the SDK.');
52 } 59 }
53 patchPaths = sdkLibrary.getPatches(platform); 60 patchPaths = sdkLibrary.getPatches(platform);
54 } 61 }
55 62
56 bool strongMode = sdk.analysisOptions.strongMode; 63 bool strongMode = sdk.analysisOptions.strongMode;
57 Context pathContext = sdk.resourceProvider.pathContext; 64 Context pathContext = sdk.resourceProvider.pathContext;
58 for (String path in patchPaths) { 65 for (String path in patchPaths) {
59 String pathInLib = pathContext.joinAll(path.split('/')); 66 String pathInLib = pathContext.joinAll(path.split('/'));
60 File patchFile = sdk.libraryDirectory.getChildAssumingFile(pathInLib); 67 File patchFile = sdk.libraryDirectory.getChildAssumingFile(pathInLib);
61 if (!patchFile.exists) { 68 if (!patchFile.exists) {
62 throw new ArgumentError( 69 throw new ArgumentError(
63 'The patch file ${patchFile.path} for $source does not exist.'); 70 'The patch file ${patchFile.path} for $source does not exist.');
64 } 71 }
65 Source patchSource = patchFile.createSource(); 72 Source patchSource = patchFile.createSource();
66 CompilationUnit patchUnit = parse(patchSource, strongMode, errorListener); 73 CompilationUnit patchUnit = parse(patchSource, strongMode, errorListener);
67 74
68 // Prepare for reporting errors. 75 // Prepare for reporting errors.
69 _baseDesc = source.toString(); 76 _baseDesc = source.toString();
70 _patchDesc = patchFile.path; 77 _patchDesc = patchFile.path;
71 _patchUnit = patchUnit; 78 _patchUnit = patchUnit;
72 79
73 _patchDirectives( 80 if (isLibraryDefiningUnit) {
74 source, unit, patchSource, patchUnit, addNewTopLevelDeclarations); 81 _patchDirectives(source, unit, patchSource, patchUnit);
75 _patchTopLevelDeclarations(unit, patchUnit, addNewTopLevelDeclarations); 82 }
83 _patchTopLevelDeclarations(unit, patchUnit, isLibraryDefiningUnit);
76 } 84 }
77 } 85 }
78 86
79 void _failExternalKeyword(String name, int offset) { 87 void _failExternalKeyword(String name, int offset) {
80 throw new ArgumentError( 88 throw new ArgumentError(
81 'The keyword "external" was expected for "$name" in $_baseDesc @ $offset .'); 89 'The keyword "external" was expected for "$name" in $_baseDesc @ $offset .');
82 } 90 }
83 91
84 void _failIfPublicName(AstNode node, String name) { 92 void _failIfPublicName(AstNode node, String name) {
85 if (!Identifier.isPrivateName(name)) { 93 if (!Identifier.isPrivateName(name)) {
(...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after
195 String className = patchClass.name.name; 203 String className = patchClass.name.name;
196 _failInPatch('contains an unsupported class member in $className', 204 _failInPatch('contains an unsupported class member in $className',
197 patchMember.offset); 205 patchMember.offset);
198 } 206 }
199 } 207 }
200 // Append new class members. 208 // Append new class members.
201 _appendToNodeList( 209 _appendToNodeList(
202 baseClass.members, membersToAppend, baseClass.leftBracket); 210 baseClass.members, membersToAppend, baseClass.leftBracket);
203 } 211 }
204 212
205 void _patchDirectives( 213 void _patchDirectives(Source baseSource, CompilationUnit baseUnit,
206 Source baseSource, 214 Source patchSource, CompilationUnit patchUnit) {
207 CompilationUnit baseUnit,
208 Source patchSource,
209 CompilationUnit patchUnit,
210 bool addNewTopLevelDeclarations) {
211 for (Directive patchDirective in patchUnit.directives) { 215 for (Directive patchDirective in patchUnit.directives) {
212 if (patchDirective is ImportDirective) { 216 if (patchDirective is ImportDirective) {
213 baseUnit.directives.add(patchDirective); 217 baseUnit.directives.add(patchDirective);
214 } else { 218 } else {
215 _failInPatch('contains an unsupported "$patchDirective" directive', 219 _failInPatch('contains an unsupported "$patchDirective" directive',
216 patchDirective.offset); 220 patchDirective.offset);
217 } 221 }
218 } 222 }
219 } 223 }
220 224
221 void _patchTopLevelDeclarations(CompilationUnit baseUnit, 225 void _patchTopLevelDeclarations(CompilationUnit baseUnit,
222 CompilationUnit patchUnit, bool addNewTopLevelDeclarations) { 226 CompilationUnit patchUnit, bool appendNewTopLevelDeclarations) {
223 List<CompilationUnitMember> declarationsToAppend = []; 227 List<CompilationUnitMember> declarationsToAppend = [];
224 for (CompilationUnitMember patchDeclaration in patchUnit.declarations) { 228 for (CompilationUnitMember patchDeclaration in patchUnit.declarations) {
225 if (patchDeclaration is FunctionDeclaration) { 229 if (patchDeclaration is FunctionDeclaration) {
226 String name = patchDeclaration.name.name; 230 String name = patchDeclaration.name.name;
227 if (_hasPatchAnnotation(patchDeclaration.metadata)) { 231 if (_hasPatchAnnotation(patchDeclaration.metadata)) {
228 for (CompilationUnitMember baseDeclaration in baseUnit.declarations) { 232 for (CompilationUnitMember baseDeclaration in baseUnit.declarations) {
229 if (patchDeclaration is FunctionDeclaration && 233 if (patchDeclaration is FunctionDeclaration &&
230 baseDeclaration is FunctionDeclaration && 234 baseDeclaration is FunctionDeclaration &&
231 baseDeclaration.name.name == name) { 235 baseDeclaration.name.name == name) {
232 // Remove the "external" keyword. 236 // Remove the "external" keyword.
233 Token externalKeyword = baseDeclaration.externalKeyword; 237 Token externalKeyword = baseDeclaration.externalKeyword;
234 if (externalKeyword != null) { 238 if (externalKeyword != null) {
235 baseDeclaration.externalKeyword = null; 239 baseDeclaration.externalKeyword = null;
236 _removeToken(externalKeyword); 240 _removeToken(externalKeyword);
237 } else { 241 } else {
238 _failExternalKeyword(name, baseDeclaration.offset); 242 _failExternalKeyword(name, baseDeclaration.offset);
239 } 243 }
240 // Replace the body. 244 // Replace the body.
241 FunctionExpression oldExpr = baseDeclaration.functionExpression; 245 FunctionExpression oldExpr = baseDeclaration.functionExpression;
242 FunctionBody newBody = patchDeclaration.functionExpression.body; 246 FunctionBody newBody = patchDeclaration.functionExpression.body;
243 _replaceNodeTokens(oldExpr.body, newBody); 247 _replaceNodeTokens(oldExpr.body, newBody);
244 oldExpr.body = newBody; 248 oldExpr.body = newBody;
245 } 249 }
246 } 250 }
247 } else if (addNewTopLevelDeclarations) { 251 } else if (appendNewTopLevelDeclarations) {
248 _failIfPublicName(patchDeclaration, name); 252 _failIfPublicName(patchDeclaration, name);
249 declarationsToAppend.add(patchDeclaration); 253 declarationsToAppend.add(patchDeclaration);
250 } 254 }
251 } else if (patchDeclaration is FunctionTypeAlias) { 255 } else if (patchDeclaration is FunctionTypeAlias) {
252 if (patchDeclaration.metadata.isNotEmpty) { 256 if (patchDeclaration.metadata.isNotEmpty) {
253 _failInPatch('contains a function type alias with an annotation', 257 _failInPatch('contains a function type alias with an annotation',
254 patchDeclaration.offset); 258 patchDeclaration.offset);
255 } 259 }
256 _failIfPublicName(patchDeclaration, patchDeclaration.name.name); 260 _failIfPublicName(patchDeclaration, patchDeclaration.name.name);
257 declarationsToAppend.add(patchDeclaration); 261 declarationsToAppend.add(patchDeclaration);
258 } else if (patchDeclaration is ClassDeclaration) { 262 } else if (patchDeclaration is ClassDeclaration) {
259 if (_hasPatchAnnotation(patchDeclaration.metadata)) { 263 if (_hasPatchAnnotation(patchDeclaration.metadata)) {
260 String name = patchDeclaration.name.name; 264 String name = patchDeclaration.name.name;
261 for (CompilationUnitMember baseDeclaration in baseUnit.declarations) { 265 for (CompilationUnitMember baseDeclaration in baseUnit.declarations) {
262 if (baseDeclaration is ClassDeclaration && 266 if (baseDeclaration is ClassDeclaration &&
263 baseDeclaration.name.name == name) { 267 baseDeclaration.name.name == name) {
264 _patchClassMembers(baseDeclaration, patchDeclaration); 268 _patchClassMembers(baseDeclaration, patchDeclaration);
265 } 269 }
266 } 270 }
267 } else { 271 } else {
268 _failIfPublicName(patchDeclaration, patchDeclaration.name.name); 272 _failIfPublicName(patchDeclaration, patchDeclaration.name.name);
269 declarationsToAppend.add(patchDeclaration); 273 declarationsToAppend.add(patchDeclaration);
270 } 274 }
271 } else { 275 } else {
272 _failInPatch('contains an unsupported top-level declaration', 276 _failInPatch('contains an unsupported top-level declaration',
273 patchDeclaration.offset); 277 patchDeclaration.offset);
274 } 278 }
275 } 279 }
276 // Append new top-level declarations. 280 // Append new top-level declarations.
277 _appendToNodeList(baseUnit.declarations, declarationsToAppend, 281 if (appendNewTopLevelDeclarations) {
278 baseUnit.endToken.previous); 282 _appendToNodeList(baseUnit.declarations, declarationsToAppend,
283 baseUnit.endToken.previous);
284 }
279 } 285 }
280 286
281 /** 287 /**
282 * Parse the given [source] into AST. 288 * Parse the given [source] into AST.
283 */ 289 */
284 @visibleForTesting 290 @visibleForTesting
285 static CompilationUnit parse( 291 static CompilationUnit parse(
286 Source source, bool strong, AnalysisErrorListener errorListener) { 292 Source source, bool strong, AnalysisErrorListener errorListener) {
287 String code = source.contents.data; 293 String code = source.contents.data;
288 294
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
334 } 340 }
335 341
336 /** 342 /**
337 * Replace tokens of the [oldNode] with tokens of the [newNode]. 343 * Replace tokens of the [oldNode] with tokens of the [newNode].
338 */ 344 */
339 static void _replaceNodeTokens(AstNode oldNode, AstNode newNode) { 345 static void _replaceNodeTokens(AstNode oldNode, AstNode newNode) {
340 oldNode.beginToken.previous.setNext(newNode.beginToken); 346 oldNode.beginToken.previous.setNext(newNode.beginToken);
341 newNode.endToken.setNext(oldNode.endToken.next); 347 newNode.endToken.setNext(oldNode.endToken.next);
342 } 348 }
343 } 349 }
OLDNEW
« no previous file with comments | « no previous file | pkg/analyzer/test/src/dart/sdk/patch_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698