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 332 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
343 | 343 |
344 void patchClass(Compiler compiler, | 344 void patchClass(Compiler compiler, |
345 ClassElementX origin, | 345 ClassElementX origin, |
346 ClassElementX patch) { | 346 ClassElementX patch) { |
347 if (origin.isPatched) { | 347 if (origin.isPatched) { |
348 compiler.internalError(origin, | 348 compiler.internalError(origin, |
349 "Patching the same class more than once."); | 349 "Patching the same class more than once."); |
350 } | 350 } |
351 origin.applyPatch(patch); | 351 origin.applyPatch(patch); |
352 checkNativeAnnotation(compiler, patch); | 352 checkNativeAnnotation(compiler, patch); |
| 353 checkJsInteropAnnotation(compiler, patch); |
353 } | 354 } |
354 | 355 |
355 /// Check whether [cls] has a `@Native(...)` annotation, and if so, set its | 356 /// Check whether [cls] has a `@Native(...)` annotation, and if so, set its |
356 /// native name from the annotation. | 357 /// native name from the annotation. |
357 checkNativeAnnotation(Compiler compiler, ClassElement cls) { | 358 checkNativeAnnotation(Compiler compiler, ClassElement cls) { |
358 EagerAnnotationHandler.checkAnnotation(compiler, cls, | 359 EagerAnnotationHandler.checkAnnotation(compiler, cls, |
359 const NativeAnnotationHandler()); | 360 const NativeAnnotationHandler()); |
360 } | 361 } |
361 | 362 |
| 363 checkJsInteropAnnotation(Compiler compiler, ClassElement cls) { |
| 364 EagerAnnotationHandler.checkAnnotation(compiler, cls, |
| 365 const JsInteropAnnotationHandler()); |
| 366 } |
| 367 |
| 368 |
362 /// Abstract interface for pre-resolution detection of metadata. | 369 /// Abstract interface for pre-resolution detection of metadata. |
363 /// | 370 /// |
364 /// The detection is handled in two steps: | 371 /// The detection is handled in two steps: |
365 /// - match the annotation syntactically and assume that the annotation is valid | 372 /// - match the annotation syntactically and assume that the annotation is valid |
366 /// if it looks correct, | 373 /// if it looks correct, |
367 /// - setup a deferred action to check that the annotation has a valid constant | 374 /// - setup a deferred action to check that the annotation has a valid constant |
368 /// value and report an internal error if not. | 375 /// value and report an internal error if not. |
369 abstract class EagerAnnotationHandler<T> { | 376 abstract class EagerAnnotationHandler<T> { |
370 /// Checks that [annotation] looks like a matching annotation and optionally | 377 /// Checks that [annotation] looks like a matching annotation and optionally |
371 /// applies actions on [element]. Returns a non-null annotation marker if the | 378 /// applies actions on [element]. Returns a non-null annotation marker if the |
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
442 Element element, | 449 Element element, |
443 MetadataAnnotation annotation, | 450 MetadataAnnotation annotation, |
444 ConstantValue constant) { | 451 ConstantValue constant) { |
445 if (constant.getType(compiler.coreTypes).element != | 452 if (constant.getType(compiler.coreTypes).element != |
446 compiler.nativeAnnotationClass) { | 453 compiler.nativeAnnotationClass) { |
447 compiler.internalError(annotation, 'Invalid @Native(...) annotation.'); | 454 compiler.internalError(annotation, 'Invalid @Native(...) annotation.'); |
448 } | 455 } |
449 } | 456 } |
450 } | 457 } |
451 | 458 |
| 459 /// Annotation handler for pre-resolution detection of `@JsName(...)` |
| 460 /// annotations. |
| 461 class JsInteropAnnotationHandler implements EagerAnnotationHandler<String> { |
| 462 const JsInteropAnnotationHandler(); |
| 463 |
| 464 String getJsNameAnnotation(MetadataAnnotation annotation) { |
| 465 if (annotation.beginToken != null && |
| 466 annotation.beginToken.next.value == 'JsName') { |
| 467 // Skipping '@', 'JsName', and '('. |
| 468 Token argument = annotation.beginToken.next.next.next; |
| 469 return (argument is StringToken) ? argument.value : ''; |
| 470 } |
| 471 |
| 472 return null; |
| 473 } |
| 474 |
| 475 String apply(Compiler compiler, |
| 476 Element element, |
| 477 MetadataAnnotation annotation) { |
| 478 if (element.isClass) { |
| 479 String jsName = getJsNameAnnotation(annotation); |
| 480 if (jsName != null) { |
| 481 ClassElementX declaration = element.declaration; |
| 482 // We do not track the class names for JsName annotations as we are not |
| 483 // concerned about checked mode errors these classes. |
| 484 declaration.isJsInterop = true; |
| 485 return jsName; |
| 486 } |
| 487 } |
| 488 return null; |
| 489 } |
| 490 |
| 491 @override |
| 492 void validate(Compiler compiler, |
| 493 Element element, |
| 494 MetadataAnnotation annotation, |
| 495 ConstantValue constant) { |
| 496 } |
| 497 } |
| 498 |
452 /// Annotation handler for pre-resolution detection of `@patch` annotations. | 499 /// Annotation handler for pre-resolution detection of `@patch` annotations. |
453 class PatchAnnotationHandler implements EagerAnnotationHandler<PatchVersion> { | 500 class PatchAnnotationHandler implements EagerAnnotationHandler<PatchVersion> { |
454 const PatchAnnotationHandler(); | 501 const PatchAnnotationHandler(); |
455 | 502 |
456 PatchVersion getPatchVersion(MetadataAnnotation annotation) { | 503 PatchVersion getPatchVersion(MetadataAnnotation annotation) { |
457 if (annotation.beginToken != null) { | 504 if (annotation.beginToken != null) { |
458 if (annotation.beginToken.next.value == 'patch') { | 505 if (annotation.beginToken.next.value == 'patch') { |
459 return const PatchVersion(null); | 506 return const PatchVersion(null); |
460 } else if (annotation.beginToken.next.value == 'patch_full') { | 507 } else if (annotation.beginToken.next.value == 'patch_full') { |
461 return const PatchVersion('full'); | 508 return const PatchVersion('full'); |
(...skipping 129 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
591 | 638 |
592 class PatchVersion { | 639 class PatchVersion { |
593 final String tag; | 640 final String tag; |
594 | 641 |
595 const PatchVersion(this.tag); | 642 const PatchVersion(this.tag); |
596 | 643 |
597 bool isActive(String patchTag) => tag == null || tag == patchTag; | 644 bool isActive(String patchTag) => tag == null || tag == patchTag; |
598 | 645 |
599 String toString() => 'PatchVersion($tag)'; | 646 String toString() => 'PatchVersion($tag)'; |
600 } | 647 } |
OLD | NEW |