| OLD | NEW |
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, 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 * This library contains the infrastructure to parse and integrate patch files. | 6 * This library contains the infrastructure to parse and integrate patch files. |
| 7 * | 7 * |
| 8 * Three types of elements can be patched: [LibraryElement], [ClassElement], | 8 * Three types of elements can be patched: [LibraryElement], [ClassElement], |
| 9 * [FunctionElement]. Patches are introduced in patch libraries which are loaded | 9 * [FunctionElement]. Patches are introduced in patch libraries which are loaded |
| 10 * together with the corresponding origin library. Which libraries that are | 10 * together with the corresponding origin library. Which libraries that are |
| (...skipping 209 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 220 | 220 |
| 221 PatchMemberListener(Compiler compiler, ClassElement enclosingClass) | 221 PatchMemberListener(Compiler compiler, ClassElement enclosingClass) |
| 222 : this.compiler = compiler, | 222 : this.compiler = compiler, |
| 223 super(compiler.parsingContext.getScannerOptionsFor(enclosingClass), | 223 super(compiler.parsingContext.getScannerOptionsFor(enclosingClass), |
| 224 compiler.reporter, enclosingClass); | 224 compiler.reporter, enclosingClass); |
| 225 | 225 |
| 226 @override | 226 @override |
| 227 void addMember(Element patch) { | 227 void addMember(Element patch) { |
| 228 addMetadata(patch); | 228 addMetadata(patch); |
| 229 | 229 |
| 230 PatchVersion patchVersion = getPatchVersion(compiler, patch); | 230 if (_isMarkedAsPatch(compiler, patch)) { |
| 231 if (patchVersion != null) { | 231 Element origin = enclosingClass.origin.localLookup(patch.name); |
| 232 if (patchVersion.isActive(compiler.patchVersion)) { | 232 patchElement(compiler, reporter, origin, patch); |
| 233 Element origin = enclosingClass.origin.localLookup(patch.name); | 233 enclosingClass.addMember(patch, reporter); |
| 234 patchElement(compiler, reporter, origin, patch); | |
| 235 enclosingClass.addMember(patch, reporter); | |
| 236 } else { | |
| 237 // Skip this element. | |
| 238 } | |
| 239 } else { | 234 } else { |
| 240 if (Name.isPublicName(patch.name)) { | 235 if (Name.isPublicName(patch.name)) { |
| 241 reporter.reportErrorMessage(patch, MessageKind.INJECTED_PUBLIC_MEMBER); | 236 reporter.reportErrorMessage(patch, MessageKind.INJECTED_PUBLIC_MEMBER); |
| 242 } | 237 } |
| 243 enclosingClass.addMember(patch, reporter); | 238 enclosingClass.addMember(patch, reporter); |
| 244 } | 239 } |
| 245 } | 240 } |
| 246 } | 241 } |
| 247 | 242 |
| 248 /** | 243 /** |
| 249 * Extension of [ElementListener] for parsing patch files. | 244 * Extension of [ElementListener] for parsing patch files. |
| 250 */ | 245 */ |
| 251 class PatchElementListener extends ElementListener implements Listener { | 246 class PatchElementListener extends ElementListener implements Listener { |
| 252 final Compiler compiler; | 247 final Compiler compiler; |
| 253 | 248 |
| 254 PatchElementListener(Compiler compiler, CompilationUnitElement patchElement, | 249 PatchElementListener(Compiler compiler, CompilationUnitElement patchElement, |
| 255 IdGenerator idGenerator) | 250 IdGenerator idGenerator) |
| 256 : this.compiler = compiler, | 251 : this.compiler = compiler, |
| 257 super(compiler.parsingContext.getScannerOptionsFor(patchElement), | 252 super(compiler.parsingContext.getScannerOptionsFor(patchElement), |
| 258 compiler.reporter, patchElement, idGenerator); | 253 compiler.reporter, patchElement, idGenerator); |
| 259 | 254 |
| 260 @override | 255 @override |
| 261 void pushElement(Element patch) { | 256 void pushElement(Element patch) { |
| 262 popMetadata(patch); | 257 popMetadata(patch); |
| 263 | 258 |
| 264 PatchVersion patchVersion = getPatchVersion(compiler, patch); | 259 if (_isMarkedAsPatch(compiler, patch)) { |
| 265 if (patchVersion != null) { | 260 LibraryElement originLibrary = compilationUnitElement.library; |
| 266 if (patchVersion.isActive(compiler.patchVersion)) { | 261 assert(originLibrary.isPatched); |
| 267 LibraryElement originLibrary = compilationUnitElement.library; | 262 Element origin = originLibrary.localLookup(patch.name); |
| 268 assert(originLibrary.isPatched); | 263 patchElement(compiler, reporter, origin, patch); |
| 269 Element origin = originLibrary.localLookup(patch.name); | 264 compilationUnitElement.addMember(patch, reporter); |
| 270 patchElement(compiler, reporter, origin, patch); | |
| 271 compilationUnitElement.addMember(patch, reporter); | |
| 272 } else { | |
| 273 // Skip this element. | |
| 274 } | |
| 275 } else { | 265 } else { |
| 276 if (Name.isPublicName(patch.name)) { | 266 if (Name.isPublicName(patch.name)) { |
| 277 reporter.reportErrorMessage(patch, MessageKind.INJECTED_PUBLIC_MEMBER); | 267 reporter.reportErrorMessage(patch, MessageKind.INJECTED_PUBLIC_MEMBER); |
| 278 } | 268 } |
| 279 compilationUnitElement.addMember(patch, reporter); | 269 compilationUnitElement.addMember(patch, reporter); |
| 280 } | 270 } |
| 281 } | 271 } |
| 282 } | 272 } |
| 283 | 273 |
| 284 void patchElement(Compiler compiler, DiagnosticReporter reporter, | 274 void patchElement(Compiler compiler, DiagnosticReporter reporter, |
| (...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 374 } | 364 } |
| 375 } | 365 } |
| 376 return handler.defaultResult; | 366 return handler.defaultResult; |
| 377 } | 367 } |
| 378 | 368 |
| 379 /// Result that signals the absence of annotations. | 369 /// Result that signals the absence of annotations. |
| 380 T get defaultResult => null; | 370 T get defaultResult => null; |
| 381 } | 371 } |
| 382 | 372 |
| 383 /// Annotation handler for pre-resolution detection of `@patch` annotations. | 373 /// Annotation handler for pre-resolution detection of `@patch` annotations. |
| 384 class PatchAnnotationHandler extends EagerAnnotationHandler<PatchVersion> { | 374 class PatchAnnotationHandler extends EagerAnnotationHandler<bool> { |
| 385 const PatchAnnotationHandler(); | 375 const PatchAnnotationHandler(); |
| 386 | 376 |
| 387 PatchVersion getPatchVersion(MetadataAnnotationX annotation) { | 377 @override |
| 388 if (annotation.beginToken != null) { | 378 bool apply( |
| 389 if (annotation.beginToken.next.lexeme == 'patch') { | 379 Compiler compiler, Element element, MetadataAnnotation annotation) { |
| 390 return const PatchVersion(null); | 380 MetadataAnnotationX meta = annotation; |
| 391 } else if (annotation.beginToken.next.lexeme == 'patch_full') { | 381 if (meta.beginToken?.next?.lexeme == 'patch') { |
| 392 return const PatchVersion('full'); | 382 return true; |
| 393 } else if (annotation.beginToken.next.lexeme == 'patch_lazy') { | |
| 394 return const PatchVersion('lazy'); | |
| 395 } else if (annotation.beginToken.next.lexeme == 'patch_startup') { | |
| 396 return const PatchVersion('startup'); | |
| 397 } | |
| 398 } | 383 } |
| 399 return null; | 384 return null; |
| 400 } | 385 } |
| 401 | 386 |
| 402 @override | 387 @override |
| 403 PatchVersion apply( | |
| 404 Compiler compiler, Element element, MetadataAnnotation annotation) { | |
| 405 return getPatchVersion(annotation); | |
| 406 } | |
| 407 | |
| 408 @override | |
| 409 void validate(Compiler compiler, Element element, | 388 void validate(Compiler compiler, Element element, |
| 410 MetadataAnnotation annotation, ConstantValue constant) { | 389 MetadataAnnotation annotation, ConstantValue constant) { |
| 411 ResolutionDartType annotationType = | 390 ResolutionDartType annotationType = |
| 412 constant.getType(compiler.commonElements); | 391 constant.getType(compiler.commonElements); |
| 413 if (annotationType.element != | 392 if (annotationType.element != |
| 414 compiler.commonElements.patchAnnotationClass) { | 393 compiler.commonElements.patchAnnotationClass) { |
| 415 DiagnosticReporter reporter = compiler.reporter; | 394 DiagnosticReporter reporter = compiler.reporter; |
| 416 reporter.internalError(annotation, 'Invalid patch annotation.'); | 395 reporter.internalError(annotation, 'Invalid patch annotation.'); |
| 417 } | 396 } |
| 418 } | 397 } |
| (...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 513 ]); | 492 ]); |
| 514 return; | 493 return; |
| 515 } | 494 } |
| 516 if (origin.isPatched) { | 495 if (origin.isPatched) { |
| 517 reporter.internalError( | 496 reporter.internalError( |
| 518 origin, "Trying to patch a function more than once."); | 497 origin, "Trying to patch a function more than once."); |
| 519 } | 498 } |
| 520 origin.applyPatch(patch); | 499 origin.applyPatch(patch); |
| 521 } | 500 } |
| 522 | 501 |
| 523 PatchVersion getPatchVersion(Compiler compiler, Element element) { | 502 bool _isMarkedAsPatch(Compiler compiler, Element element) { |
| 524 return EagerAnnotationHandler.checkAnnotation( | 503 return EagerAnnotationHandler.checkAnnotation( |
| 525 compiler, element, const PatchAnnotationHandler()); | 504 compiler, element, const PatchAnnotationHandler()) == |
| 505 true; |
| 526 } | 506 } |
| 527 | |
| 528 class PatchVersion { | |
| 529 final String tag; | |
| 530 | |
| 531 const PatchVersion(this.tag); | |
| 532 | |
| 533 bool isActive(String patchTag) => tag == null || tag == patchTag; | |
| 534 | |
| 535 String toString() => 'PatchVersion($tag)'; | |
| 536 } | |
| OLD | NEW |