| /* |
| * @(#)DeclarationFilter.java 1.2 04/07/19 |
| * |
| * Copyright (c) 2004, Sun Microsystems, Inc. |
| * All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions are met: |
| * |
| * * Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * * Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in the |
| * documentation and/or other materials provided with the distribution. |
| * * Neither the name of the Sun Microsystems, Inc. nor the names of |
| * its contributors may be used to endorse or promote products derived from |
| * this software without specific prior written permission. |
| * |
| * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS |
| * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
| * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A |
| * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER |
| * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
| * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
| * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
| * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
| * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
| * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
| * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| package com.sun.mirror.util; |
| |
| |
| import java.util.ArrayList; |
| import java.util.Collection; |
| |
| import com.sun.mirror.declaration.Declaration; |
| import com.sun.mirror.declaration.Modifier; |
| |
| import static com.sun.mirror.declaration.Modifier.*; |
| |
| |
| /** |
| * A filter for selecting just the items of interest |
| * from a collection of declarations. |
| * The filter is said to <i>select</i> or to <i>match</i> those declarations. |
| * Filters can be created in several ways: |
| * by the static methods described below, |
| * by negating or composing existing filters, |
| * or by subclasses that implement arbitrary matching rules. |
| * |
| * <p> A subclass can create an arbitrary filter simply by implementing |
| * the {@link #matches(Declaration)} method. |
| * |
| * <p> Examples. |
| * <p> Selecting the <tt>public</tt> declarations from a collection: |
| * <blockquote><pre> |
| * result = FILTER_PUBLIC.filter(decls); </pre></blockquote> |
| * Selecting class declarations (including enums): |
| * <blockquote><pre> |
| * classFilter = DeclarationFilter.getFilter(ClassDeclaration.class); |
| * result = classFilter.filter(decls); </pre></blockquote> |
| * Selecting class declarations but excluding enums: |
| * <blockquote><pre> |
| * enumFilter = DeclarationFilter.getFilter(EnumDeclaration.class); |
| * compoundFilter = classFilter.and(enumFilter.not()); |
| * result = compoundFilter.filter(decls); </pre></blockquote> |
| * Selecting declarations named "Bob": |
| * <blockquote><pre> |
| * nameFilter = new DeclarationFilter() { |
| * public boolean matches(Declaration d) { |
| * return d.getSimpleName().equals("Bob"); |
| * } |
| * }; |
| * result = nameFilter.filter(decls); </pre></blockquote> |
| * |
| * @author Joseph D. Darcy |
| * @author Scott Seligman |
| * @version 1.2 04/07/19 |
| * @since 1.5 |
| */ |
| |
| public class DeclarationFilter { |
| |
| // Predefined filters for convenience. |
| |
| /** |
| * A filter that selects only <tt>public</tt> declarations. |
| */ |
| public static final DeclarationFilter FILTER_PUBLIC = |
| new AccessFilter(PUBLIC); |
| |
| /** |
| * A filter that selects only <tt>protected</tt> declarations. |
| */ |
| public static final DeclarationFilter FILTER_PROTECTED = |
| new AccessFilter(PROTECTED); |
| |
| /** |
| * A filter that selects only <tt>public</tt> or <tt>protected</tt> |
| * declarations. |
| */ |
| public static final DeclarationFilter FILTER_PUBLIC_OR_PROTECTED = |
| new AccessFilter(PUBLIC, PROTECTED); |
| |
| /** |
| * A filter that selects only package-private (<i>default</i>) |
| * declarations. |
| */ |
| public static final DeclarationFilter FILTER_PACKAGE = |
| new AccessFilter(); |
| |
| /** |
| * A filter that selects only <tt>private</tt> declarations. |
| */ |
| public static final DeclarationFilter FILTER_PRIVATE = |
| new AccessFilter(PRIVATE); |
| |
| |
| /** |
| * Constructs an identity filter: one that selects all declarations. |
| */ |
| public DeclarationFilter() { |
| } |
| |
| |
| |
| // Methods to create a filter. |
| |
| /** |
| * Returns a filter that selects declarations containing all of a |
| * collection of modifiers. |
| * |
| * @param mods the modifiers to match (non-null) |
| * @return a filter that matches declarations containing <tt>mods</tt> |
| */ |
| public static DeclarationFilter getFilter( |
| final Collection<Modifier> mods) { |
| return new DeclarationFilter() { |
| public boolean matches(Declaration d) { |
| return d.getModifiers().containsAll(mods); |
| } |
| }; |
| } |
| |
| /** |
| * Returns a filter that selects declarations of a particular kind. |
| * For example, there may be a filter that selects only class |
| * declarations, or only fields. |
| * The filter will select declarations of the specified kind, |
| * and also any subtypes of that kind; for example, a field filter |
| * will also select enum constants. |
| * |
| * @param kind the kind of declarations to select |
| * @return a filter that selects declarations of a particular kind |
| */ |
| public static DeclarationFilter getFilter( |
| final Class<? extends Declaration> kind) { |
| return new DeclarationFilter() { |
| public boolean matches(Declaration d) { |
| return kind.isInstance(d); |
| } |
| }; |
| } |
| |
| /** |
| * Returns a filter that selects those declarations selected |
| * by both this filter and another. |
| * |
| * @param f filter to be composed with this one |
| * @return a filter that selects those declarations selected by |
| * both this filter and another |
| */ |
| public DeclarationFilter and(DeclarationFilter f) { |
| final DeclarationFilter f1 = this; |
| final DeclarationFilter f2 = f; |
| return new DeclarationFilter() { |
| public boolean matches(Declaration d) { |
| return f1.matches(d) && f2.matches(d); |
| } |
| }; |
| } |
| |
| /** |
| * Returns a filter that selects those declarations selected |
| * by either this filter or another. |
| * |
| * @param f filter to be composed with this one |
| * @return a filter that selects those declarations selected by |
| * either this filter or another |
| */ |
| public DeclarationFilter or(DeclarationFilter f) { |
| final DeclarationFilter f1 = this; |
| final DeclarationFilter f2 = f; |
| return new DeclarationFilter() { |
| public boolean matches(Declaration d) { |
| return f1.matches(d) || f2.matches(d); |
| } |
| }; |
| } |
| |
| /** |
| * Returns a filter that selects those declarations not selected |
| * by this filter. |
| * |
| * @return a filter that selects those declarations not selected |
| * by this filter |
| */ |
| public DeclarationFilter not() { |
| return new DeclarationFilter() { |
| public boolean matches(Declaration d) { |
| return !DeclarationFilter.this.matches(d); |
| } |
| }; |
| } |
| |
| |
| |
| // Methods to apply a filter. |
| |
| /** |
| * Tests whether this filter matches a given declaration. |
| * The default implementation always returns <tt>true</tt>; |
| * subclasses should override this. |
| * |
| * @param decl the declaration to match |
| * @return <tt>true</tt> if this filter matches the given declaration |
| */ |
| public boolean matches(Declaration decl) { |
| return true; |
| } |
| |
| /** |
| * Returns the declarations matched by this filter. |
| * The result is a collection of the same type as the argument; |
| * the {@linkplain #filter(Collection, Class) two-parameter version} |
| * of <tt>filter</tt> offers control over the result type. |
| * |
| * @param <D> type of the declarations being filtered |
| * @param decls declarations being filtered |
| * @return the declarations matched by this filter |
| */ |
| public <D extends Declaration> Collection<D> filter(Collection<D> decls) { |
| ArrayList<D> res = new ArrayList<D>(decls.size()); |
| for (D d : decls) { |
| if (matches(d)) { |
| res.add(d); |
| } |
| } |
| return res; |
| } |
| |
| /** |
| * Returns the declarations matched by this filter, with the result |
| * being restricted to declarations of a given kind. |
| * Similar to the simpler |
| * {@linkplain #filter(Collection) single-parameter version} |
| * of <tt>filter</tt>, but the result type is specified explicitly. |
| * |
| * @param <D> type of the declarations being returned |
| * @param decls declarations being filtered |
| * @param resType type of the declarations being returned -- |
| * the reflective view of <tt>D</tt> |
| * @return the declarations matched by this filter, restricted to those |
| * of the specified type |
| */ |
| public <D extends Declaration> Collection<D> |
| filter(Collection<? extends Declaration> decls, Class<D> resType) { |
| ArrayList<D> res = new ArrayList<D>(decls.size()); |
| for (Declaration d : decls) { |
| if (resType.isInstance(d) && matches(d)) { |
| res.add(resType.cast(d)); |
| } |
| } |
| return res; |
| } |
| |
| |
| |
| /* |
| * A filter based on access modifiers. |
| */ |
| private static class AccessFilter extends DeclarationFilter { |
| |
| // The first access modifier to filter on, or null if we're looking |
| // for declarations with no access modifiers. |
| private Modifier mod1 = null; |
| |
| // The second access modifier to filter on, or null if none. |
| private Modifier mod2 = null; |
| |
| // Returns a filter that matches declarations with no access |
| // modifiers. |
| AccessFilter() { |
| } |
| |
| // Returns a filter that matches m. |
| AccessFilter(Modifier m) { |
| mod1 = m; |
| } |
| |
| // Returns a filter that matches either m1 or m2. |
| AccessFilter(Modifier m1, Modifier m2) { |
| mod1 = m1; |
| mod2 = m2; |
| } |
| |
| public boolean matches(Declaration d) { |
| Collection<Modifier> mods = d.getModifiers(); |
| if (mod1 == null) { // looking for package private |
| return !(mods.contains(PUBLIC) || |
| mods.contains(PROTECTED) || |
| mods.contains(PRIVATE)); |
| } |
| return mods.contains(mod1) && |
| (mod2 == null || mods.contains(mod2)); |
| } |
| } |
| } |