318 lines
10 KiB
Java
Executable File
318 lines
10 KiB
Java
Executable File
/*
|
|
* @(#)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/>
|
|
* <p> A subclass can create an arbitrary filter simply by implementing
|
|
* the {@link #matches(Declaration)} method.
|
|
* <p/>
|
|
* <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));
|
|
}
|
|
}
|
|
}
|