1. /*
  2. * @(#)DeclarationFilter.java 1.2 04/07/19
  3. *
  4. * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
  5. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  6. */
  7. package com.sun.mirror.util;
  8. import java.util.ArrayList;
  9. import java.util.Collection;
  10. import com.sun.mirror.declaration.Declaration;
  11. import com.sun.mirror.declaration.Modifier;
  12. import static com.sun.mirror.declaration.Modifier.*;
  13. /**
  14. * A filter for selecting just the items of interest
  15. * from a collection of declarations.
  16. * The filter is said to <i>select</i> or to <i>match</i> those declarations.
  17. * Filters can be created in several ways:
  18. * by the static methods described below,
  19. * by negating or composing existing filters,
  20. * or by subclasses that implement arbitrary matching rules.
  21. *
  22. * <p> A subclass can create an arbitrary filter simply by implementing
  23. * the {@link #matches(Declaration)} method.
  24. *
  25. * <p> Examples.
  26. * <p> Selecting the <tt>public</tt> declarations from a collection:
  27. * <blockquote><pre>
  28. * result = FILTER_PUBLIC.filter(decls); </pre></blockquote>
  29. * Selecting class declarations (including enums):
  30. * <blockquote><pre>
  31. * classFilter = DeclarationFilter.getFilter(ClassDeclaration.class);
  32. * result = classFilter.filter(decls); </pre></blockquote>
  33. * Selecting class declarations but excluding enums:
  34. * <blockquote><pre>
  35. * enumFilter = DeclarationFilter.getFilter(EnumDeclaration.class);
  36. * compoundFilter = classFilter.and(enumFilter.not());
  37. * result = compoundFilter.filter(decls); </pre></blockquote>
  38. * Selecting declarations named "Bob":
  39. * <blockquote><pre>
  40. * nameFilter = new DeclarationFilter() {
  41. * public boolean matches(Declaration d) {
  42. * return d.getSimpleName().equals("Bob");
  43. * }
  44. * };
  45. * result = nameFilter.filter(decls); </pre></blockquote>
  46. *
  47. * @author Joseph D. Darcy
  48. * @author Scott Seligman
  49. * @version 1.2 04/07/19
  50. * @since 1.5
  51. */
  52. public class DeclarationFilter {
  53. // Predefined filters for convenience.
  54. /**
  55. * A filter that selects only <tt>public</tt> declarations.
  56. */
  57. public static final DeclarationFilter FILTER_PUBLIC =
  58. new AccessFilter(PUBLIC);
  59. /**
  60. * A filter that selects only <tt>protected</tt> declarations.
  61. */
  62. public static final DeclarationFilter FILTER_PROTECTED =
  63. new AccessFilter(PROTECTED);
  64. /**
  65. * A filter that selects only <tt>public</tt> or <tt>protected</tt>
  66. * declarations.
  67. */
  68. public static final DeclarationFilter FILTER_PUBLIC_OR_PROTECTED =
  69. new AccessFilter(PUBLIC, PROTECTED);
  70. /**
  71. * A filter that selects only package-private (<i>default</i>)
  72. * declarations.
  73. */
  74. public static final DeclarationFilter FILTER_PACKAGE =
  75. new AccessFilter();
  76. /**
  77. * A filter that selects only <tt>private</tt> declarations.
  78. */
  79. public static final DeclarationFilter FILTER_PRIVATE =
  80. new AccessFilter(PRIVATE);
  81. /**
  82. * Constructs an identity filter: one that selects all declarations.
  83. */
  84. public DeclarationFilter() {
  85. }
  86. // Methods to create a filter.
  87. /**
  88. * Returns a filter that selects declarations containing all of a
  89. * collection of modifiers.
  90. *
  91. * @param mods the modifiers to match (non-null)
  92. * @return a filter that matches declarations containing <tt>mods</tt>
  93. */
  94. public static DeclarationFilter getFilter(
  95. final Collection<Modifier> mods) {
  96. return new DeclarationFilter() {
  97. public boolean matches(Declaration d) {
  98. return d.getModifiers().containsAll(mods);
  99. }
  100. };
  101. }
  102. /**
  103. * Returns a filter that selects declarations of a particular kind.
  104. * For example, there may be a filter that selects only class
  105. * declarations, or only fields.
  106. * The filter will select declarations of the specified kind,
  107. * and also any subtypes of that kind; for example, a field filter
  108. * will also select enum constants.
  109. *
  110. * @param kind the kind of declarations to select
  111. * @return a filter that selects declarations of a particular kind
  112. */
  113. public static DeclarationFilter getFilter(
  114. final Class<? extends Declaration> kind) {
  115. return new DeclarationFilter() {
  116. public boolean matches(Declaration d) {
  117. return kind.isInstance(d);
  118. }
  119. };
  120. }
  121. /**
  122. * Returns a filter that selects those declarations selected
  123. * by both this filter and another.
  124. *
  125. * @param f filter to be composed with this one
  126. * @return a filter that selects those declarations selected by
  127. * both this filter and another
  128. */
  129. public DeclarationFilter and(DeclarationFilter f) {
  130. final DeclarationFilter f1 = this;
  131. final DeclarationFilter f2 = f;
  132. return new DeclarationFilter() {
  133. public boolean matches(Declaration d) {
  134. return f1.matches(d) && f2.matches(d);
  135. }
  136. };
  137. }
  138. /**
  139. * Returns a filter that selects those declarations selected
  140. * by either this filter or another.
  141. *
  142. * @param f filter to be composed with this one
  143. * @return a filter that selects those declarations selected by
  144. * either this filter or another
  145. */
  146. public DeclarationFilter or(DeclarationFilter f) {
  147. final DeclarationFilter f1 = this;
  148. final DeclarationFilter f2 = f;
  149. return new DeclarationFilter() {
  150. public boolean matches(Declaration d) {
  151. return f1.matches(d) || f2.matches(d);
  152. }
  153. };
  154. }
  155. /**
  156. * Returns a filter that selects those declarations not selected
  157. * by this filter.
  158. *
  159. * @return a filter that selects those declarations not selected
  160. * by this filter
  161. */
  162. public DeclarationFilter not() {
  163. return new DeclarationFilter() {
  164. public boolean matches(Declaration d) {
  165. return !DeclarationFilter.this.matches(d);
  166. }
  167. };
  168. }
  169. // Methods to apply a filter.
  170. /**
  171. * Tests whether this filter matches a given declaration.
  172. * The default implementation always returns <tt>true</tt>
  173. * subclasses should override this.
  174. *
  175. * @param decl the declaration to match
  176. * @return <tt>true</tt> if this filter matches the given declaration
  177. */
  178. public boolean matches(Declaration decl) {
  179. return true;
  180. }
  181. /**
  182. * Returns the declarations matched by this filter.
  183. * The result is a collection of the same type as the argument;
  184. * the {@linkplain #filter(Collection, Class) two-parameter version}
  185. * of <tt>filter</tt> offers control over the result type.
  186. *
  187. * @param <D> type of the declarations being filtered
  188. * @param decls declarations being filtered
  189. * @return the declarations matched by this filter
  190. */
  191. public <D extends Declaration> Collection<D> filter(Collection<D> decls) {
  192. ArrayList<D> res = new ArrayList<D>(decls.size());
  193. for (D d : decls) {
  194. if (matches(d)) {
  195. res.add(d);
  196. }
  197. }
  198. return res;
  199. }
  200. /**
  201. * Returns the declarations matched by this filter, with the result
  202. * being restricted to declarations of a given kind.
  203. * Similar to the simpler
  204. * {@linkplain #filter(Collection) single-parameter version}
  205. * of <tt>filter</tt>, but the result type is specified explicitly.
  206. *
  207. * @param <D> type of the declarations being returned
  208. * @param decls declarations being filtered
  209. * @param resType type of the declarations being returned --
  210. * the reflective view of <tt>D</tt>
  211. * @return the declarations matched by this filter, restricted to those
  212. * of the specified type
  213. */
  214. public <D extends Declaration> Collection<D>
  215. filter(Collection<? extends Declaration> decls, Class<D> resType) {
  216. ArrayList<D> res = new ArrayList<D>(decls.size());
  217. for (Declaration d : decls) {
  218. if (resType.isInstance(d) && matches(d)) {
  219. res.add(resType.cast(d));
  220. }
  221. }
  222. return res;
  223. }
  224. /*
  225. * A filter based on access modifiers.
  226. */
  227. private static class AccessFilter extends DeclarationFilter {
  228. // The first access modifier to filter on, or null if we're looking
  229. // for declarations with no access modifiers.
  230. private Modifier mod1 = null;
  231. // The second access modifier to filter on, or null if none.
  232. private Modifier mod2 = null;
  233. // Returns a filter that matches declarations with no access
  234. // modifiers.
  235. AccessFilter() {
  236. }
  237. // Returns a filter that matches m.
  238. AccessFilter(Modifier m) {
  239. mod1 = m;
  240. }
  241. // Returns a filter that matches either m1 or m2.
  242. AccessFilter(Modifier m1, Modifier m2) {
  243. mod1 = m1;
  244. mod2 = m2;
  245. }
  246. public boolean matches(Declaration d) {
  247. Collection<Modifier> mods = d.getModifiers();
  248. if (mod1 == null) { // looking for package private
  249. return !(mods.contains(PUBLIC) ||
  250. mods.contains(PROTECTED) ||
  251. mods.contains(PRIVATE));
  252. }
  253. return mods.contains(mod1) &&
  254. (mod2 == null || mods.contains(mod2));
  255. }
  256. }
  257. }