| /******************************************************************************* |
| * Copyright (c) 2007, 2014 IBM Corporation and others. |
| * |
| * This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License 2.0 |
| * which accompanies this distribution, and is available at |
| * https://www.eclipse.org/legal/epl-2.0/ |
| * |
| * SPDX-License-Identifier: EPL-2.0 |
| * |
| * Contributors: |
| * IBM Corporation - initial API and implementation |
| *******************************************************************************/ |
| package org.eclipse.pde.api.tools.internal; |
| |
| import java.util.ArrayList; |
| import java.util.Collection; |
| import java.util.Collections; |
| import java.util.HashMap; |
| import java.util.HashSet; |
| import java.util.LinkedHashMap; |
| import java.util.List; |
| import java.util.Set; |
| |
| import org.eclipse.pde.api.tools.internal.provisional.IApiJavadocTag; |
| import org.eclipse.pde.api.tools.internal.provisional.RestrictionModifiers; |
| |
| /** |
| * Manages contributed javadoc tags. This manager is lazy, in that nothing is |
| * loaded until it is asked for. |
| * |
| * @since 1.0.0 |
| */ |
| public final class JavadocTagManager { |
| |
| /** |
| * Compound key for the annotation cache |
| * |
| * @since 1.0.600 |
| */ |
| class Key { |
| int type; |
| int member; |
| |
| public Key(int t, int m) { |
| type = t; |
| member = m; |
| } |
| |
| @Override |
| public boolean equals(Object obj) { |
| if (obj instanceof Key) { |
| Key other = (Key) obj; |
| return type == other.type && member == other.member; |
| } |
| return super.equals(obj); |
| } |
| |
| @Override |
| public int hashCode() { |
| return type + member; |
| } |
| } |
| |
| /** |
| * Constant for the <code>noinsantiate</code> tag <br> |
| * <br> |
| * Value is: <code>@noinstantiate</code> |
| * |
| * @since 1.0.500 |
| */ |
| public static final String TAG_NOINSTANTIATE = "@noinstantiate"; //$NON-NLS-1$ |
| /** |
| * Constant for the <code>@NoInstantiate</code> annotation <br> |
| * <br> |
| * Value is: <code>NoInstantiate</code> |
| * |
| * @since 1.0.600 |
| */ |
| public static final String ANNOTATION_NOINSTANTIATE = "NoInstantiate"; //$NON-NLS-1$ |
| /** |
| * Constant for the <code>noextend</code> tag <br> |
| * <br> |
| * Value is: <code>@noextend</code> |
| * |
| * @since 1.0.500 |
| */ |
| public static final String TAG_NOEXTEND = "@noextend"; //$NON-NLS-1$ |
| /** |
| * Constant for the <code>@NoExtend</code> annotation <br> |
| * <br> |
| * Value is: <code>NoExtend</code> |
| * |
| * @since 1.0.600 |
| */ |
| public static final String ANNOTATION_NOEXTEND = "NoExtend"; //$NON-NLS-1$ |
| /** |
| * Constant for the <code>noimplement</code> tag <br> |
| * <br> |
| * Value is: <code>@noimplement</code> |
| * |
| * @since 1.0.500 |
| */ |
| public static final String TAG_NOIMPLEMENT = "@noimplement"; //$NON-NLS-1$ |
| /** |
| * Constant for the <code>@NoImplement</code> annotation <br> |
| * <br> |
| * Value is: <code>NoImplement</code> |
| * |
| * @since 1.0.600 |
| */ |
| public static final String ANNOTATION_NOIMPLEMENT = "NoImplement"; //$NON-NLS-1$ |
| /** |
| * Constant for the <code>nooverride</code> tag <br> |
| * <br> |
| * Value is: <code>@nooverride</code> |
| * |
| * @since 1.0.500 |
| */ |
| public static final String TAG_NOOVERRIDE = "@nooverride"; //$NON-NLS-1$ |
| /** |
| * Constant for the <code>@NoOverride</code> annotation <br> |
| * <br> |
| * Value is: <code>NoOverride</code> |
| * |
| * @since 1.0.600 |
| */ |
| public static final String ANNOTATION_NOOVERRIDE = "NoOverride"; //$NON-NLS-1$ |
| /** |
| * Constant for the <code>noreference</code> tag <br> |
| * <br> |
| * Value is: <code>@noreference</code> |
| * |
| * @since 1.0.500 |
| */ |
| public static final String TAG_NOREFERENCE = "@noreference"; //$NON-NLS-1$ |
| /** |
| * Constant for the <code>@NoReference</code> annotation <br> |
| * <br> |
| * Value is: <code>NoReference</code> |
| * |
| * @since 1.0.600 |
| */ |
| public static final String ANNOTATION_NOREFERENCE = "NoReference"; //$NON-NLS-1$ |
| |
| /** |
| * The collection of all tags |
| * |
| * @see #TAG_NOEXTEND |
| * @see #TAG_NOIMPLEMENT |
| * @see #TAG_NOINSTANTIATE |
| * @see #TAG_NOOVERRIDE |
| * @see #TAG_NOREFERENCE |
| */ |
| public static final Set<String> ALL_TAGS; |
| |
| /** |
| * The collection of all annotation names |
| * |
| * @see #ANNOTATION_NOEXTEND |
| * @see #ANNOTATION_NOIMPLEMENT |
| * @see #ANNOTATION_NOINSTANTIATE |
| * @see #ANNOTATION_NOOVERRIDE |
| * @see #ANNOTATION_NOREFERENCE |
| * |
| * @sine 1.0.600 |
| */ |
| public static final Set<String> ALL_ANNOTATIONS; |
| |
| /** |
| * Cache for simple annotation names mapped to their fully qualified name |
| * |
| * @since 1.0.600 |
| */ |
| private static final HashMap<String, String> fqAnnotationNames; |
| |
| static { |
| HashSet<String> tags = new HashSet<>(5, 1); |
| tags.add(TAG_NOEXTEND); |
| tags.add(TAG_NOIMPLEMENT); |
| tags.add(TAG_NOINSTANTIATE); |
| tags.add(TAG_NOOVERRIDE); |
| tags.add(TAG_NOREFERENCE); |
| ALL_TAGS = Collections.unmodifiableSet(tags); |
| |
| tags = new HashSet<>(); |
| tags.add(ANNOTATION_NOEXTEND); |
| tags.add(ANNOTATION_NOIMPLEMENT); |
| tags.add(ANNOTATION_NOINSTANTIATE); |
| tags.add(ANNOTATION_NOOVERRIDE); |
| tags.add(ANNOTATION_NOREFERENCE); |
| ALL_ANNOTATIONS = Collections.unmodifiableSet(tags); |
| |
| fqAnnotationNames = new HashMap<>(); |
| fqAnnotationNames.put(ANNOTATION_NOEXTEND, "org.eclipse.pde.api.tools.annotations.NoExtend"); //$NON-NLS-1$ |
| fqAnnotationNames.put(ANNOTATION_NOIMPLEMENT, "org.eclipse.pde.api.tools.annotations.NoImplement"); //$NON-NLS-1$ |
| fqAnnotationNames.put(ANNOTATION_NOINSTANTIATE, "org.eclipse.pde.api.tools.annotations.NoInstantiate"); //$NON-NLS-1$ |
| fqAnnotationNames.put(ANNOTATION_NOOVERRIDE, "org.eclipse.pde.api.tools.annotations.NoOverride"); //$NON-NLS-1$ |
| fqAnnotationNames.put(ANNOTATION_NOREFERENCE, "org.eclipse.pde.api.tools.annotations.NoReference"); //$NON-NLS-1$ |
| } |
| |
| /** |
| * Cache for the contributed javadoc tags. Cache form: |
| */ |
| private HashMap<String, IApiJavadocTag> tagcache = null; |
| |
| /** |
| * Cache of annotations keyed by the member the apply to |
| * |
| * @since 1.0.600 |
| */ |
| private HashMap<Key, Set<String>> fAnnotationCache = null; |
| |
| /** |
| * Collection of tag extensions |
| */ |
| private IApiJavadocTag[] tags; |
| |
| /** |
| * Initialize the annotation mapping |
| * |
| * @since 1.0.600 |
| */ |
| private void initializeAnnotations() { |
| if (fAnnotationCache == null) { |
| fAnnotationCache = new HashMap<>(); |
| HashSet<String> annots = new HashSet<>(); |
| annots.add(ANNOTATION_NOEXTEND); |
| annots.add(ANNOTATION_NOINSTANTIATE); |
| annots.add(ANNOTATION_NOREFERENCE); |
| fAnnotationCache.put(new Key(IApiJavadocTag.TYPE_CLASS, IApiJavadocTag.MEMBER_NONE), annots); |
| annots = new HashSet<>(); |
| annots.add(ANNOTATION_NOEXTEND); |
| annots.add(ANNOTATION_NOIMPLEMENT); |
| annots.add(ANNOTATION_NOREFERENCE); |
| fAnnotationCache.put(new Key(IApiJavadocTag.TYPE_INTERFACE, IApiJavadocTag.MEMBER_NONE), annots); |
| annots = new HashSet<>(); |
| annots.add(ANNOTATION_NOOVERRIDE); |
| annots.add(ANNOTATION_NOREFERENCE); |
| fAnnotationCache.put(new Key(IApiJavadocTag.TYPE_CLASS, IApiJavadocTag.MEMBER_METHOD), annots); |
| fAnnotationCache.put(new Key(IApiJavadocTag.TYPE_CLASS, IApiJavadocTag.MEMBER_CONSTRUCTOR), annots); |
| fAnnotationCache.put(new Key(IApiJavadocTag.TYPE_INTERFACE, IApiJavadocTag.MEMBER_METHOD), annots); |
| annots = new HashSet<>(); |
| annots.add(ANNOTATION_NOREFERENCE); |
| fAnnotationCache.put(new Key(IApiJavadocTag.TYPE_CLASS, IApiJavadocTag.MEMBER_FIELD), annots); |
| fAnnotationCache.put(new Key(IApiJavadocTag.TYPE_INTERFACE, IApiJavadocTag.MEMBER_FIELD), annots); |
| fAnnotationCache.put(new Key(IApiJavadocTag.TYPE_ANNOTATION, IApiJavadocTag.MEMBER_NONE), annots); |
| fAnnotationCache.put(new Key(IApiJavadocTag.TYPE_ENUM, IApiJavadocTag.MEMBER_NONE), annots); |
| fAnnotationCache.put(new Key(IApiJavadocTag.TYPE_ENUM, IApiJavadocTag.MEMBER_FIELD), annots); |
| fAnnotationCache.put(new Key(IApiJavadocTag.TYPE_ENUM, IApiJavadocTag.MEMBER_METHOD), annots); |
| |
| } |
| } |
| |
| /** |
| * Initializes the cache of contributed Javadoc tags. If the cache has |
| * already been initialized no work is done. |
| */ |
| private void initializeJavadocTags() { |
| if (tagcache == null) { |
| tagcache = new LinkedHashMap<>(); |
| List<ApiJavadocTag> list = new ArrayList<>(4); |
| |
| // noimplement tag |
| ApiJavadocTag newtag = new ApiJavadocTag(IApiJavadocTag.NO_IMPLEMENT_TAG_ID, "noimplement", //$NON-NLS-1$ |
| RestrictionModifiers.NO_IMPLEMENT); |
| newtag.setApplicableTo(IApiJavadocTag.TYPE_INTERFACE, IApiJavadocTag.MEMBER_NONE, CoreMessages.JavadocTagManager_interface_no_implement); |
| tagcache.put(newtag.getTagId(), newtag); |
| list.add(newtag); |
| |
| // noextend tag |
| newtag = new ApiJavadocTag(IApiJavadocTag.NO_EXTEND_TAG_ID, "noextend", //$NON-NLS-1$ |
| RestrictionModifiers.NO_EXTEND); |
| newtag.setApplicableTo(IApiJavadocTag.TYPE_CLASS, IApiJavadocTag.MEMBER_NONE, CoreMessages.JavadocTagManager_class_no_subclass); |
| newtag.setApplicableTo(IApiJavadocTag.TYPE_INTERFACE, IApiJavadocTag.MEMBER_NONE, CoreMessages.JavadocTagManager_interface_no_extend); |
| tagcache.put(newtag.getTagId(), newtag); |
| list.add(newtag); |
| |
| // nooverride tag |
| newtag = new ApiJavadocTag(IApiJavadocTag.NO_OVERRIDE_TAG_ID, "nooverride", //$NON-NLS-1$ |
| RestrictionModifiers.NO_OVERRIDE); |
| newtag.setApplicableTo(IApiJavadocTag.TYPE_CLASS, IApiJavadocTag.MEMBER_METHOD, CoreMessages.JavadocTagManager_method_no_overried); |
| newtag.setApplicableTo(IApiJavadocTag.TYPE_INTERFACE, IApiJavadocTag.MEMBER_METHOD, CoreMessages.JavadocTagManager_default_method_no_override); |
| tagcache.put(newtag.getTagId(), newtag); |
| list.add(newtag); |
| |
| // noinstantiate tag |
| newtag = new ApiJavadocTag(IApiJavadocTag.NO_INSTANTIATE_TAG_ID, "noinstantiate", //$NON-NLS-1$ |
| RestrictionModifiers.NO_INSTANTIATE); |
| newtag.setApplicableTo(IApiJavadocTag.TYPE_CLASS, IApiJavadocTag.MEMBER_NONE, CoreMessages.JavadocTagManager_class_no_instantiate); |
| tagcache.put(newtag.getTagId(), newtag); |
| list.add(newtag); |
| |
| // noreference tag |
| newtag = new ApiJavadocTag(IApiJavadocTag.NO_REFERENCE_TAG_ID, "noreference", //$NON-NLS-1$ |
| RestrictionModifiers.NO_REFERENCE); |
| newtag.setApplicableTo(IApiJavadocTag.TYPE_CLASS, IApiJavadocTag.MEMBER_NONE, CoreMessages.JavadocTagManager_class_no_reference); |
| newtag.setApplicableTo(IApiJavadocTag.TYPE_CLASS, IApiJavadocTag.MEMBER_METHOD, CoreMessages.JavadocTagManager_method_no_reference); |
| newtag.setApplicableTo(IApiJavadocTag.TYPE_CLASS, IApiJavadocTag.MEMBER_CONSTRUCTOR, CoreMessages.JavadocTagManager_constructor_no_reference); |
| newtag.setApplicableTo(IApiJavadocTag.TYPE_CLASS, IApiJavadocTag.MEMBER_FIELD, CoreMessages.JavadocTagManager_field_no_reference); |
| newtag.setApplicableTo(IApiJavadocTag.TYPE_INTERFACE, IApiJavadocTag.MEMBER_METHOD, CoreMessages.JavadocTagManager_method_no_reference); |
| newtag.setApplicableTo(IApiJavadocTag.TYPE_INTERFACE, IApiJavadocTag.MEMBER_FIELD, CoreMessages.JavadocTagManager_field_no_reference); |
| newtag.setApplicableTo(IApiJavadocTag.TYPE_INTERFACE, IApiJavadocTag.MEMBER_NONE, CoreMessages.JavadocTagManager_interface_no_reference); |
| newtag.setApplicableTo(IApiJavadocTag.TYPE_ENUM, IApiJavadocTag.MEMBER_NONE, CoreMessages.JavadocTagManager_enum_no_reference); |
| newtag.setApplicableTo(IApiJavadocTag.TYPE_ENUM, IApiJavadocTag.MEMBER_FIELD, CoreMessages.JavadocTagManager_enum_field_no_reference); |
| newtag.setApplicableTo(IApiJavadocTag.TYPE_ENUM, IApiJavadocTag.MEMBER_METHOD, CoreMessages.JavadocTagManager_enum_method_no_reference); |
| newtag.setApplicableTo(IApiJavadocTag.TYPE_ANNOTATION, IApiJavadocTag.MEMBER_NONE, CoreMessages.JavadocTagManager_annotation_no_reference); |
| tagcache.put(newtag.getTagId(), newtag); |
| list.add(newtag); |
| tags = list.toArray(new IApiJavadocTag[list.size()]); |
| } |
| } |
| |
| /** |
| * Returns all of the java doc tags for a given kind of type and member. See |
| * {@link IApiJavadocTag} for a complete listing of tag Java type and member |
| * types. |
| * |
| * @param type one of <code>CLASS</code> or <code>INTERFACE</code> |
| * @param member one of <code>METHOD</code> or <code>FIELD</code> or |
| * <code>NONE</code> |
| * @return an array of {@link IApiJavadocTag}s that apply to the specified |
| * Java type or an empty array, never <code>null</code> |
| */ |
| public synchronized IApiJavadocTag[] getTagsForType(int type, int member) { |
| initializeJavadocTags(); |
| List<IApiJavadocTag> list = new ArrayList<>(); |
| for (IApiJavadocTag tag : tags) { |
| if (tag.isApplicable(type, member)) { |
| list.add(tag); |
| } |
| } |
| return list.toArray(new IApiJavadocTag[list.size()]); |
| } |
| |
| /** |
| * Returns the set of supported annotations for the given type and member |
| * |
| * @param type the type kind |
| * @param member the member kind |
| * @return the set of supported annotations or an empty set, never |
| * <code>null</code> |
| * @since 1.0.600 |
| */ |
| public synchronized Set<String> getAnntationsForType(int type, int member) { |
| initializeAnnotations(); |
| Set<String> values = fAnnotationCache.get(new Key(type, member)); |
| if (values != null) { |
| return values; |
| } |
| return Collections.EMPTY_SET; |
| } |
| |
| /** |
| * Returns the fully qualified name of the class providing the annotation |
| * with the given simple type name. <code>null</code> is returned if the |
| * annotation is unknown. <br> |
| * <br> |
| * Example: <code>NoExtend</code> returns |
| * <code>org.eclipse.pde.api.toools.annnotations.NoExtend</code> |
| * |
| * @param typename |
| * @return the fully qualified type name of the annotation or |
| * <code>null</code> if unknown |
| * |
| * @since 1.0.600 |
| */ |
| public synchronized String getQualifiedNameForAnnotation(String typename) { |
| return fqAnnotationNames.get(typename); |
| } |
| |
| /** |
| * Returns the {@link IApiJavadocTag} that has the given id or |
| * <code>null</code> if there is no tag with the given id |
| * |
| * @param id the id of the tag to fetch |
| * @return the {@link IApiJavadocTag} with the given id or <code>null</code> |
| */ |
| public synchronized IApiJavadocTag getTag(String id) { |
| initializeJavadocTags(); |
| return tagcache.get(id); |
| } |
| |
| /** |
| * Returns the complete listing of {@link IApiJavadocTag}s contained in the |
| * manager or an empty array, never <code>null</code> |
| * |
| * @return the complete listing of tags in the manager or <code>null</code> |
| */ |
| public synchronized IApiJavadocTag[] getAllTags() { |
| initializeJavadocTags(); |
| if (tagcache == null) { |
| return new IApiJavadocTag[0]; |
| } |
| Collection<IApiJavadocTag> values = tagcache.values(); |
| return values.toArray(new IApiJavadocTag[values.size()]); |
| } |
| |
| /** |
| * @return The complete set of tags names that this manager currently knows |
| * about. |
| */ |
| public synchronized Set<String> getAllTagNames() { |
| IApiJavadocTag[] tags = getAllTags(); |
| HashSet<String> names = new HashSet<>(tags.length); |
| for (IApiJavadocTag tag : tags) { |
| names.add(tag.getTagName()); |
| } |
| return names; |
| } |
| |
| /** |
| * Returns the restriction modifier set on the javadoc tag with the given |
| * name. If the manager has no entry for the specified tag name |
| * <code>-1</code> is returned. |
| * |
| * @param tagname the name of the tag |
| * @param type one of <code>CLASS</code> or <code>INTERFACE</code> |
| * @param member one of <code>METHOD</code> or <code>FIELD</code> or |
| * <code>NONE</code> |
| * @return the restriction modifier for the given tag name or |
| * {@link RestrictionModifiers#NO_RESTRICTIONS} if not found |
| */ |
| public synchronized int getRestrictionsForTag(String tagname, int type, int member) { |
| if (tagname == null) { |
| return RestrictionModifiers.NO_RESTRICTIONS; |
| } |
| initializeJavadocTags(); |
| for (IApiJavadocTag tag : tags) { |
| if (tag.getTagName().equals(tagname) && (tag.isApplicable(type, member))) { |
| return tag.getRestrictionModifier(); |
| } |
| } |
| return RestrictionModifiers.NO_RESTRICTIONS; |
| } |
| } |