2420 } |
2418 } |
2421 |
2419 |
2422 /** Check the annotations of a symbol. |
2420 /** Check the annotations of a symbol. |
2423 */ |
2421 */ |
2424 public void validateAnnotations(List<JCAnnotation> annotations, Symbol s) { |
2422 public void validateAnnotations(List<JCAnnotation> annotations, Symbol s) { |
2425 if (skipAnnotations) return; |
|
2426 for (JCAnnotation a : annotations) |
2423 for (JCAnnotation a : annotations) |
2427 validateAnnotation(a, s); |
2424 validateAnnotation(a, s); |
2428 } |
2425 } |
2429 |
2426 |
2430 /** Check an annotation of a symbol. |
2427 /** Check an annotation of a symbol. |
2431 */ |
2428 */ |
2432 public void validateAnnotation(JCAnnotation a, Symbol s) { |
2429 private void validateAnnotation(JCAnnotation a, Symbol s) { |
2433 validateAnnotationTree(a); |
2430 validateAnnotationTree(a); |
2434 |
2431 |
2435 if (!annotationApplicable(a, s)) |
2432 if (!annotationApplicable(a, s)) |
2436 log.error(a.pos(), "annotation.type.not.applicable"); |
2433 log.error(a.pos(), "annotation.type.not.applicable"); |
2437 |
2434 |
2438 if (a.annotationType.type.tsym == syms.overrideType.tsym) { |
2435 if (a.annotationType.type.tsym == syms.overrideType.tsym) { |
2439 if (!isOverrider(s)) |
2436 if (!isOverrider(s)) |
2440 log.error(a.pos(), "method.does.not.override.superclass"); |
2437 log.error(a.pos(), "method.does.not.override.superclass"); |
2441 } |
2438 } |
|
2439 } |
|
2440 |
|
2441 /** |
|
2442 * Validate the proposed container 'containedBy' on the |
|
2443 * annotation type symbol 's'. Report errors at position |
|
2444 * 'pos'. |
|
2445 * |
|
2446 * @param s The (annotation)type declaration annotated with a @ContainedBy |
|
2447 * @param containerAnno the @ContainedBy on 's' |
|
2448 * @param pos where to report errors |
|
2449 */ |
|
2450 public void validateContainedBy(TypeSymbol s, Attribute.Compound containedBy, DiagnosticPosition pos) { |
|
2451 Assert.check(types.isSameType(containedBy.type, syms.containedByType)); |
|
2452 |
|
2453 Type t = null; |
|
2454 List<Pair<MethodSymbol,Attribute>> l = containedBy.values; |
|
2455 if (!l.isEmpty()) { |
|
2456 Assert.check(l.head.fst.name == names.value); |
|
2457 t = ((Attribute.Class)l.head.snd).getValue(); |
|
2458 } |
|
2459 |
|
2460 if (t == null) { |
|
2461 log.error(pos, "invalid.container.wrong.containedby", s, containedBy); |
|
2462 return; |
|
2463 } |
|
2464 |
|
2465 validateHasContainerFor(t.tsym, s, pos); |
|
2466 validateRetention(t.tsym, s, pos); |
|
2467 validateDocumented(t.tsym, s, pos); |
|
2468 validateInherited(t.tsym, s, pos); |
|
2469 validateTarget(t.tsym, s, pos); |
|
2470 } |
|
2471 |
|
2472 /** |
|
2473 * Validate the proposed container 'containerFor' on the |
|
2474 * annotation type symbol 's'. Report errors at position |
|
2475 * 'pos'. |
|
2476 * |
|
2477 * @param s The (annotation)type declaration annotated with a @ContainerFor |
|
2478 * @param containerFor the @ContainedFor on 's' |
|
2479 * @param pos where to report errors |
|
2480 */ |
|
2481 public void validateContainerFor(TypeSymbol s, Attribute.Compound containerFor, DiagnosticPosition pos) { |
|
2482 Assert.check(types.isSameType(containerFor.type, syms.containerForType)); |
|
2483 |
|
2484 Type t = null; |
|
2485 List<Pair<MethodSymbol,Attribute>> l = containerFor.values; |
|
2486 if (!l.isEmpty()) { |
|
2487 Assert.check(l.head.fst.name == names.value); |
|
2488 t = ((Attribute.Class)l.head.snd).getValue(); |
|
2489 } |
|
2490 |
|
2491 if (t == null) { |
|
2492 log.error(pos, "invalid.container.wrong.containerfor", s, containerFor); |
|
2493 return; |
|
2494 } |
|
2495 |
|
2496 validateHasContainedBy(t.tsym, s, pos); |
|
2497 } |
|
2498 |
|
2499 private void validateHasContainedBy(TypeSymbol container, TypeSymbol contained, DiagnosticPosition pos) { |
|
2500 Attribute.Compound containedBy = container.attribute(syms.containedByType.tsym); |
|
2501 |
|
2502 if (containedBy == null) { |
|
2503 log.error(pos, "invalid.container.no.containedby", container, syms.containedByType.tsym); |
|
2504 return; |
|
2505 } |
|
2506 |
|
2507 Type t = null; |
|
2508 List<Pair<MethodSymbol,Attribute>> l = containedBy.values; |
|
2509 if (!l.isEmpty()) { |
|
2510 Assert.check(l.head.fst.name == names.value); |
|
2511 t = ((Attribute.Class)l.head.snd).getValue(); |
|
2512 } |
|
2513 |
|
2514 if (t == null) { |
|
2515 log.error(pos, "invalid.container.wrong.containedby", container, contained); |
|
2516 return; |
|
2517 } |
|
2518 |
|
2519 if (!types.isSameType(t, contained.type)) |
|
2520 log.error(pos, "invalid.container.wrong.containedby", t.tsym, contained); |
|
2521 } |
|
2522 |
|
2523 private void validateHasContainerFor(TypeSymbol container, TypeSymbol contained, DiagnosticPosition pos) { |
|
2524 Attribute.Compound containerFor = container.attribute(syms.containerForType.tsym); |
|
2525 |
|
2526 if (containerFor == null) { |
|
2527 log.error(pos, "invalid.container.no.containerfor", container, syms.containerForType.tsym); |
|
2528 return; |
|
2529 } |
|
2530 |
|
2531 Type t = null; |
|
2532 List<Pair<MethodSymbol,Attribute>> l = containerFor.values; |
|
2533 if (!l.isEmpty()) { |
|
2534 Assert.check(l.head.fst.name == names.value); |
|
2535 t = ((Attribute.Class)l.head.snd).getValue(); |
|
2536 } |
|
2537 |
|
2538 if (t == null) { |
|
2539 log.error(pos, "invalid.container.wrong.containerfor", container, contained); |
|
2540 return; |
|
2541 } |
|
2542 |
|
2543 if (!types.isSameType(t, contained.type)) |
|
2544 log.error(pos, "invalid.container.wrong.containerfor", t.tsym, contained); |
|
2545 } |
|
2546 |
|
2547 private void validateRetention(Symbol container, Symbol contained, DiagnosticPosition pos) { |
|
2548 Attribute.RetentionPolicy containerRetention = types.getRetention(container); |
|
2549 Attribute.RetentionPolicy containedRetention = types.getRetention(contained); |
|
2550 |
|
2551 boolean error = false; |
|
2552 switch (containedRetention) { |
|
2553 case RUNTIME: |
|
2554 if (containerRetention != Attribute.RetentionPolicy.RUNTIME) { |
|
2555 error = true; |
|
2556 } |
|
2557 break; |
|
2558 case CLASS: |
|
2559 if (containerRetention == Attribute.RetentionPolicy.SOURCE) { |
|
2560 error = true; |
|
2561 } |
|
2562 } |
|
2563 if (error ) { |
|
2564 log.error(pos, "invalid.containedby.annotation.retention", |
|
2565 container, containerRetention, |
|
2566 contained, containedRetention); |
|
2567 } |
|
2568 } |
|
2569 |
|
2570 private void validateDocumented(Symbol container, Symbol contained, DiagnosticPosition pos) { |
|
2571 if (contained.attribute(syms.documentedType.tsym) != null) { |
|
2572 if (container.attribute(syms.documentedType.tsym) == null) { |
|
2573 log.error(pos, "invalid.containedby.annotation.not.documented", container, contained); |
|
2574 } |
|
2575 } |
|
2576 } |
|
2577 |
|
2578 private void validateInherited(Symbol container, Symbol contained, DiagnosticPosition pos) { |
|
2579 if (contained.attribute(syms.inheritedType.tsym) != null) { |
|
2580 if (container.attribute(syms.inheritedType.tsym) == null) { |
|
2581 log.error(pos, "invalid.containedby.annotation.not.inherited", container, contained); |
|
2582 } |
|
2583 } |
|
2584 } |
|
2585 |
|
2586 private void validateTarget(Symbol container, Symbol contained, DiagnosticPosition pos) { |
|
2587 Attribute.Array containedTarget = getAttributeTargetAttribute(contained); |
|
2588 |
|
2589 // If contained has no Target, we are done |
|
2590 if (containedTarget == null) { |
|
2591 return; |
|
2592 } |
|
2593 |
|
2594 // If contained has Target m1, container must have a Target |
|
2595 // annotation, m2, and m2 must be a subset of m1. (This is |
|
2596 // trivially true if contained has no target as per above). |
|
2597 |
|
2598 // contained has target, but container has not, error |
|
2599 Attribute.Array containerTarget = getAttributeTargetAttribute(container); |
|
2600 if (containerTarget == null) { |
|
2601 log.error(pos, "invalid.containedby.annotation.incompatible.target", container, contained); |
|
2602 return; |
|
2603 } |
|
2604 |
|
2605 Set<Name> containerTargets = new HashSet<Name>(); |
|
2606 for (Attribute app : containerTarget.values) { |
|
2607 if (!(app instanceof Attribute.Enum)) { |
|
2608 continue; // recovery |
|
2609 } |
|
2610 Attribute.Enum e = (Attribute.Enum)app; |
|
2611 containerTargets.add(e.value.name); |
|
2612 } |
|
2613 |
|
2614 Set<Name> containedTargets = new HashSet<Name>(); |
|
2615 for (Attribute app : containedTarget.values) { |
|
2616 if (!(app instanceof Attribute.Enum)) { |
|
2617 continue; // recovery |
|
2618 } |
|
2619 Attribute.Enum e = (Attribute.Enum)app; |
|
2620 containedTargets.add(e.value.name); |
|
2621 } |
|
2622 |
|
2623 if (!isTargetSubset(containedTargets, containerTargets)) { |
|
2624 log.error(pos, "invalid.containedby.annotation.incompatible.target", container, contained); |
|
2625 } |
|
2626 } |
|
2627 |
|
2628 /** Checks that t is a subset of s, with respect to ElementType |
|
2629 * semantics, specifically {ANNOTATION_TYPE} is a subset of {TYPE} |
|
2630 */ |
|
2631 private boolean isTargetSubset(Set<Name> s, Set<Name> t) { |
|
2632 // Check that all elements in t are present in s |
|
2633 for (Name n2 : t) { |
|
2634 boolean currentElementOk = false; |
|
2635 for (Name n1 : s) { |
|
2636 if (n1 == n2) { |
|
2637 currentElementOk = true; |
|
2638 break; |
|
2639 } else if (n1 == names.TYPE && n2 == names.ANNOTATION_TYPE) { |
|
2640 currentElementOk = true; |
|
2641 break; |
|
2642 } |
|
2643 } |
|
2644 if (!currentElementOk) |
|
2645 return false; |
|
2646 } |
|
2647 return true; |
2442 } |
2648 } |
2443 |
2649 |
2444 /** Is s a method symbol that overrides a method in a superclass? */ |
2650 /** Is s a method symbol that overrides a method in a superclass? */ |
2445 boolean isOverrider(Symbol s) { |
2651 boolean isOverrider(Symbol s) { |
2446 if (s.kind != MTH || s.isStatic()) |
2652 if (s.kind != MTH || s.isStatic()) |