|
20 | 20 | import java.util.Iterator; |
21 | 21 | import java.util.Map; |
22 | 22 | import java.util.StringTokenizer; |
| 23 | +import java.util.regex.Pattern; |
| 24 | +import java.util.regex.PatternSyntaxException; |
23 | 25 |
|
24 | 26 | import org.eclipse.core.resources.IFile; |
25 | 27 | import org.eclipse.core.resources.IMarker; |
@@ -657,15 +659,54 @@ private void validateIdentifierAttribute(Element element, Attr attr, ISchemaAttr |
657 | 659 | String basedOn = attInfo.getBasedOn(); |
658 | 660 | // only validate if we have a valid value and basedOn value |
659 | 661 | if (value != null && basedOn != null && value.length() > 0 && basedOn.length() > 0) { |
660 | | - Map<String, IConfigurationElement> attributes = PDESchemaHelper.getValidAttributes(attInfo); |
661 | | - if (!attributes.containsKey(value)) { // report error if we are missing something |
| 662 | + // report error if we are missing something |
| 663 | + if (!isPresent(attInfo, value)) { |
662 | 664 | VirtualMarker marker = report(NLS.bind(PDECoreMessages.ExtensionsErrorReporter_unknownIdentifier, (new String[] {attr.getValue(), attr.getName()})), getLine(element, attr.getName()), severity, PDEMarkerFactory.CAT_OTHER); |
663 | 665 | addMarkerAttribute(marker, PDEMarkerFactory.compilerKey, CompilerFlags.P_UNKNOWN_IDENTIFIER); |
664 | 666 | } |
665 | 667 | } |
666 | 668 | } |
667 | 669 | } |
668 | 670 |
|
| 671 | + private boolean isPresent(ISchemaAttribute attInfo, String value) { |
| 672 | + // This is the normal case. |
| 673 | + Map<String, IConfigurationElement> attributes = PDESchemaHelper.getValidAttributes(attInfo); |
| 674 | + if (attributes.containsKey(value)) { |
| 675 | + return true; |
| 676 | + } |
| 677 | + // Determine if this is a special case. |
| 678 | + // https://github.com/eclipse-platform/eclipse.platform/blob/master/ua/org.eclipse.ui.intro.quicklinks/schema/quicklinks.exsd |
| 679 | + String qualifiedName = attInfo.getSchema().getPointId() + '.' + attInfo.getParent().getName() + '.' |
| 680 | + + attInfo.getName(); |
| 681 | + // The command may include simple '*' wildcards to match any substring. |
| 682 | + boolean allowsWildcard = "org.eclipse.ui.intro.quicklinks.override.command".equals(qualifiedName); //$NON-NLS-1$ |
| 683 | + // These both allow not just an ID but also a command spec as consumed |
| 684 | + // by org.eclipse.ui.commands.ICommandService.deserialize(String) |
| 685 | + boolean allowsCommandSpec = allowsWildcard |
| 686 | + || "org.eclipse.ui.intro.quicklinks.command.id".equals(qualifiedName); //$NON-NLS-1$ |
| 687 | + if (allowsCommandSpec || allowsWildcard) { |
| 688 | + String baseValue = value; |
| 689 | + // Validate just the command ID part of the command spec if present. |
| 690 | + int index = value.indexOf("("); //$NON-NLS-1$ |
| 691 | + if (index != -1) { |
| 692 | + baseValue = value.substring(0, index); |
| 693 | + } |
| 694 | + // If a simple wildcard is permitted and is present... |
| 695 | + if (allowsWildcard && baseValue.contains("*")) { //$NON-NLS-1$ |
| 696 | + try { |
| 697 | + // Convert it to a pattern and match against all keys. |
| 698 | + Pattern pattern = Pattern.compile(baseValue.replace(".", "\\.").replace("*", ".*")); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ |
| 699 | + return attributes.keySet().stream().anyMatch(pattern.asMatchPredicate()); |
| 700 | + } catch (PatternSyntaxException ex) { |
| 701 | + //$FALL-THROUGH$ |
| 702 | + } |
| 703 | + } |
| 704 | + // If we extracted a base value, test it like we did the value. |
| 705 | + return value != baseValue && attributes.containsKey(baseValue); |
| 706 | + } |
| 707 | + return false; |
| 708 | + } |
| 709 | + |
669 | 710 | protected void reportUnusedAttribute(Element element, String attName, int severity) { |
670 | 711 | String message = NLS.bind(PDECoreMessages.Builders_Manifest_unused_attribute, attName); |
671 | 712 | VirtualMarker marker = report(message, getLine(element, attName), severity, PDEMarkerFactory.CAT_OTHER); |
|
0 commit comments