|
15 | 15 | *******************************************************************************/ |
16 | 16 | package org.eclipse.jdt.internal.ui.preferences; |
17 | 17 |
|
| 18 | +import java.lang.annotation.ElementType; |
| 19 | +import java.lang.annotation.Target; |
| 20 | +import java.util.ArrayList; |
18 | 21 | import java.util.Arrays; |
| 22 | +import java.util.HashMap; |
19 | 23 | import java.util.List; |
| 24 | +import java.util.Map; |
| 25 | +import java.util.Map.Entry; |
20 | 26 |
|
21 | 27 | import org.eclipse.equinox.bidi.StructuredTextTypeHandlerFactory; |
22 | 28 | import org.eclipse.osgi.util.NLS; |
|
70 | 76 | import org.eclipse.ui.forms.widgets.ExpandableComposite; |
71 | 77 | import org.eclipse.ui.preferences.IWorkbenchPreferenceContainer; |
72 | 78 |
|
| 79 | +import org.eclipse.jdt.core.IAnnotation; |
| 80 | +import org.eclipse.jdt.core.IMemberValuePair; |
| 81 | +import org.eclipse.jdt.core.IType; |
73 | 82 | import org.eclipse.jdt.core.JavaConventions; |
74 | 83 | import org.eclipse.jdt.core.JavaCore; |
75 | 84 | import org.eclipse.jdt.core.JavaModelException; |
@@ -560,11 +569,119 @@ protected void buttonPressed(int buttonId) { |
560 | 569 | fOtherNullableAnnotationsDialogField.removeAllElements(); |
561 | 570 | fOtherNonNullAnnotationsDialogField.removeAllElements(); |
562 | 571 | fOtherNonNullByDefaultAnnotationsDialogField.removeAllElements(); |
| 572 | + } else if (buttonId == IDialogConstants.OK_ID) { |
| 573 | + Map<AnnotationTarget,List<String>> namesPerTarget= new HashMap<>(); |
| 574 | + detectedAnnotationTargets(fNullableAnnotationDialogField, fOtherNullableAnnotationsDialogField, namesPerTarget); |
| 575 | + detectedAnnotationTargets(fNonNullAnnotationDialogField, fOtherNonNullAnnotationsDialogField, namesPerTarget); |
| 576 | + if (namesPerTarget.size() > 1) { |
| 577 | + if (warnIncompatibleAnnotations(namesPerTarget) != 0) { |
| 578 | + return; |
| 579 | + } |
| 580 | + } |
| 581 | + okPressed(); |
563 | 582 | } else { |
564 | 583 | super.buttonPressed(buttonId); |
565 | 584 | } |
566 | 585 | } |
567 | 586 |
|
| 587 | + enum AnnotationTarget { NONE, DECLARATIONS, TYPE_USE, BOTH; |
| 588 | + static AnnotationTarget forMemberValuePairs(IMemberValuePair[] pairs) { |
| 589 | + AnnotationTarget result= NONE; |
| 590 | + for (IMemberValuePair pair : pairs) { |
| 591 | + int kind= pair.getValueKind(); |
| 592 | + if (kind == IMemberValuePair.K_QUALIFIED_NAME || kind == IMemberValuePair.K_SIMPLE_NAME) { |
| 593 | + for (Object val : (Object[]) pair.getValue()) { |
| 594 | + AnnotationTarget current= forName((String) val); |
| 595 | + if (result == NONE) |
| 596 | + result= current; |
| 597 | + else if (current != result) |
| 598 | + return BOTH; |
| 599 | + } |
| 600 | + } |
| 601 | + } |
| 602 | + return result; |
| 603 | + } |
| 604 | + private static AnnotationTarget forName(String name) { |
| 605 | + if (name.equals(ElementType.TYPE_USE.name()) || name.equals(ElementType.class.getName()+'.'+ElementType.TYPE_USE.name())) |
| 606 | + return AnnotationTarget.TYPE_USE; |
| 607 | + else |
| 608 | + return AnnotationTarget.DECLARATIONS; |
| 609 | + } |
| 610 | + String displayString() { |
| 611 | + return switch (this) { |
| 612 | + case NONE -> PreferencesMessages.NullAnnotationsConfigurationDialog_targetUnspecified; |
| 613 | + case TYPE_USE -> PreferencesMessages.NullAnnotationsConfigurationDialog_targetTypeuse; |
| 614 | + case DECLARATIONS -> PreferencesMessages.NullAnnotationsConfigurationDialog_targetDeclarations; |
| 615 | + case BOTH -> PreferencesMessages.NullAnnotationsConfigurationDialog_targetBoth; |
| 616 | + }; |
| 617 | + } |
| 618 | + } |
| 619 | + private void detectedAnnotationTargets(AnnotationDialogField field, AnnotationListDialogField list, Map<AnnotationTarget, List<String>> namesPerTarget) { |
| 620 | + String name1= field.getText(); |
| 621 | + AnnotationTarget target1= getAnnotationKind(name1); |
| 622 | + List<String> perTarget= namesPerTarget.computeIfAbsent(target1, k -> new ArrayList<>()); |
| 623 | + perTarget.add(name1); |
| 624 | + for (AnnotationWrapper otherWrapper : list.getElements()) { |
| 625 | + String otherName= otherWrapper.annotationName; |
| 626 | + if (otherName.isBlank()) continue; |
| 627 | + AnnotationTarget other= getAnnotationKind(otherName); |
| 628 | + perTarget= namesPerTarget.computeIfAbsent(other, k -> new ArrayList<>()); |
| 629 | + perTarget.add(otherName); |
| 630 | + } |
| 631 | + } |
| 632 | + private AnnotationTarget getAnnotationKind(String name) { |
| 633 | + try { |
| 634 | + IType annotationType= JavaCore.create(fProject).findType(name); |
| 635 | + if (annotationType != null && annotationType.exists()) { |
| 636 | + for (IAnnotation metaAnn : annotationType.getAnnotations()) { |
| 637 | + if (isTargetMetaAnnotation(metaAnn, annotationType)) { |
| 638 | + return AnnotationTarget.forMemberValuePairs(metaAnn.getMemberValuePairs()); |
| 639 | + } |
| 640 | + } |
| 641 | + } |
| 642 | + } catch (JavaModelException e) { |
| 643 | + // fall through |
| 644 | + } |
| 645 | + return AnnotationTarget.NONE; |
| 646 | + } |
| 647 | + private boolean isTargetMetaAnnotation(IAnnotation metaAnn, IType context) { |
| 648 | + String name= metaAnn.getElementName(); |
| 649 | + if (Target.class.getName().equals(name)) { |
| 650 | + return true; |
| 651 | + } else if (Target.class.getSimpleName().equals(name)) { |
| 652 | + try { |
| 653 | + String[][] resolved= context.resolveType(name); |
| 654 | + if (resolved.length == 1 && resolved[0].length == 2) { |
| 655 | + return Target.class.getPackageName().equals(resolved[0][0]); |
| 656 | + } |
| 657 | + } catch (JavaModelException e) { |
| 658 | + return false; |
| 659 | + } |
| 660 | + } |
| 661 | + return false; |
| 662 | + } |
| 663 | + private int warnIncompatibleAnnotations(Map<AnnotationTarget,List<String>> namesPerTarget) { |
| 664 | + StringBuilder message= new StringBuilder(PreferencesMessages.NullAnnotationsConfigurationDialog_incompatibleAnnotations_dialogMessage); |
| 665 | + for (Entry<AnnotationTarget, List<String>> entry : namesPerTarget.entrySet()) { |
| 666 | + message.append("\n\n\t").append(entry.getKey().displayString()).append(':'); //$NON-NLS-1$ |
| 667 | + for (String name : entry.getValue()) { |
| 668 | + message.append("\n\t\t").append(name); //$NON-NLS-1$ |
| 669 | + } |
| 670 | + } |
| 671 | + MessageDialog messageDialog= new MessageDialog( |
| 672 | + getShell(), |
| 673 | + PreferencesMessages.NullAnnotationsConfigurationDialog_incompatibleAnnotations_dialogTitle, |
| 674 | + null, |
| 675 | + message.toString(), |
| 676 | + MessageDialog.QUESTION, |
| 677 | + new String[] { IDialogConstants.YES_LABEL, IDialogConstants.CANCEL_LABEL }, |
| 678 | + 0); |
| 679 | + messageDialog.create(); |
| 680 | + Shell messageShell= messageDialog.getShell(); |
| 681 | + messageShell.setLocation(messageShell.getLocation().x, getShell().getLocation().y + 40); |
| 682 | + return messageDialog.open(); |
| 683 | + } |
| 684 | + |
568 | 685 | public String[] getResult() { |
569 | 686 | return new String[] { |
570 | 687 | fNullableAnnotationDialogField.getText(), |
|
0 commit comments