1 /*
   2  * Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package com.sun.mirror.util;
  27 
  28 
  29 import java.util.ArrayList;
  30 import java.util.Collection;
  31 
  32 import com.sun.mirror.declaration.Declaration;
  33 import com.sun.mirror.declaration.Modifier;
  34 
  35 import static com.sun.mirror.declaration.Modifier.*;
  36 
  37 
  38 /**
  39  * A filter for selecting just the items of interest
  40  * from a collection of declarations.
  41  * The filter is said to <i>select</i> or to <i>match</i> those declarations.
  42  * Filters can be created in several ways:
  43  * by the static methods described below,
  44  * by negating or composing existing filters,
  45  * or by subclasses that implement arbitrary matching rules.
  46  *
  47  * <p> A subclass can create an arbitrary filter simply by implementing
  48  * the {@link #matches(Declaration)} method.
  49  *
  50  * <p> Examples.
  51  * <p> Selecting the <tt>public</tt> declarations from a collection:
  52  * <blockquote><pre>
  53  *     result = FILTER_PUBLIC.filter(decls);            </pre></blockquote>
  54  * Selecting class declarations (including enums):
  55  * <blockquote><pre>
  56  *     classFilter = DeclarationFilter.getFilter(ClassDeclaration.class);
  57  *     result = classFilter.filter(decls);              </pre></blockquote>
  58  * Selecting class declarations but excluding enums:
  59  * <blockquote><pre>
  60  *     enumFilter = DeclarationFilter.getFilter(EnumDeclaration.class);
  61  *     compoundFilter = classFilter.and(enumFilter.not());
  62  *     result = compoundFilter.filter(decls);           </pre></blockquote>
  63  * Selecting declarations named "Bob":
  64  * <blockquote><pre>
  65  *     nameFilter = new DeclarationFilter() {
  66  *                      public boolean matches(Declaration d) {
  67  *                          return d.getSimpleName().equals("Bob");
  68  *                      }
  69  *                  };
  70  *     result = nameFilter.filter(decls);               </pre></blockquote>
  71  *
  72  * @deprecated All components of this API have been superseded by the
  73  * standardized annotation processing API.  The replacement for the
  74  * functionality of this class is {@link
  75  * javax.lang.model.util.ElementFilter}.
  76  *
  77  * @author Joseph D. Darcy
  78  * @author Scott Seligman
  79  * @since 1.5
  80  */
  81 @Deprecated
  82 @SuppressWarnings("deprecation")
  83 public class DeclarationFilter {
  84 
  85     // Predefined filters for convenience.
  86 
  87     /**
  88      * A filter that selects only <tt>public</tt> declarations.
  89      */
  90     public static final DeclarationFilter FILTER_PUBLIC =
  91             new AccessFilter(PUBLIC);
  92 
  93     /**
  94      * A filter that selects only <tt>protected</tt> declarations.
  95      */
  96     public static final DeclarationFilter FILTER_PROTECTED =
  97             new AccessFilter(PROTECTED);
  98 
  99     /**
 100      * A filter that selects only <tt>public</tt> or <tt>protected</tt>
 101      * declarations.
 102      */
 103     public static final DeclarationFilter FILTER_PUBLIC_OR_PROTECTED =
 104             new AccessFilter(PUBLIC, PROTECTED);
 105 
 106     /**
 107      * A filter that selects only package-private (<i>default</i>)
 108      * declarations.
 109      */
 110     public static final DeclarationFilter FILTER_PACKAGE =
 111             new AccessFilter();
 112 
 113     /**
 114      * A filter that selects only <tt>private</tt> declarations.
 115      */
 116     public static final DeclarationFilter FILTER_PRIVATE =
 117             new AccessFilter(PRIVATE);
 118 
 119 
 120     /**
 121      * Constructs an identity filter:  one that selects all declarations.
 122      */
 123     public DeclarationFilter() {
 124     }
 125 
 126 
 127 
 128     // Methods to create a filter.
 129 
 130     /**
 131      * Returns a filter that selects declarations containing all of a
 132      * collection of modifiers.
 133      *
 134      * @param mods  the modifiers to match (non-null)
 135      * @return a filter that matches declarations containing <tt>mods</tt>
 136      */
 137     public static DeclarationFilter getFilter(
 138                                              final Collection<Modifier> mods) {
 139         return new DeclarationFilter() {
 140             public boolean matches(Declaration d) {
 141                 return d.getModifiers().containsAll(mods);
 142             }
 143         };
 144     }
 145 
 146     /**
 147      * Returns a filter that selects declarations of a particular kind.
 148      * For example, there may be a filter that selects only class
 149      * declarations, or only fields.
 150      * The filter will select declarations of the specified kind,
 151      * and also any subtypes of that kind; for example, a field filter
 152      * will also select enum constants.
 153      *
 154      * @param kind  the kind of declarations to select
 155      * @return a filter that selects declarations of a particular kind
 156      */
 157     public static DeclarationFilter getFilter(
 158                                      final Class<? extends Declaration> kind) {
 159         return new DeclarationFilter() {
 160             public boolean matches(Declaration d) {
 161                 return kind.isInstance(d);
 162             }
 163         };
 164     }
 165 
 166     /**
 167      * Returns a filter that selects those declarations selected
 168      * by both this filter and another.
 169      *
 170      * @param f  filter to be composed with this one
 171      * @return a filter that selects those declarations selected by
 172      *          both this filter and another
 173      */
 174     public DeclarationFilter and(DeclarationFilter f) {
 175         final DeclarationFilter f1 = this;
 176         final DeclarationFilter f2 = f;
 177         return new DeclarationFilter() {
 178             public boolean matches(Declaration d) {
 179                 return f1.matches(d) && f2.matches(d);
 180             }
 181         };
 182     }
 183 
 184     /**
 185      * Returns a filter that selects those declarations selected
 186      * by either this filter or another.
 187      *
 188      * @param f  filter to be composed with this one
 189      * @return a filter that selects those declarations selected by
 190      *          either this filter or another
 191      */
 192     public DeclarationFilter or(DeclarationFilter f) {
 193         final DeclarationFilter f1 = this;
 194         final DeclarationFilter f2 = f;
 195         return new DeclarationFilter() {
 196             public boolean matches(Declaration d) {
 197                 return f1.matches(d) || f2.matches(d);
 198             }
 199         };
 200     }
 201 
 202     /**
 203      * Returns a filter that selects those declarations not selected
 204      * by this filter.
 205      *
 206      * @return a filter that selects those declarations not selected
 207      * by this filter
 208      */
 209     public DeclarationFilter not() {
 210         return new DeclarationFilter() {
 211             public boolean matches(Declaration d) {
 212                 return !DeclarationFilter.this.matches(d);
 213             }
 214         };
 215     }
 216 
 217 
 218 
 219     // Methods to apply a filter.
 220 
 221     /**
 222      * Tests whether this filter matches a given declaration.
 223      * The default implementation always returns <tt>true</tt>;
 224      * subclasses should override this.
 225      *
 226      * @param decl  the declaration to match
 227      * @return <tt>true</tt> if this filter matches the given declaration
 228      */
 229     public boolean matches(Declaration decl) {
 230         return true;
 231     }
 232 
 233     /**
 234      * Returns the declarations matched by this filter.
 235      * The result is a collection of the same type as the argument;
 236      * the {@linkplain #filter(Collection, Class) two-parameter version}
 237      * of <tt>filter</tt> offers control over the result type.
 238      *
 239      * @param <D>    type of the declarations being filtered
 240      * @param decls  declarations being filtered
 241      * @return the declarations matched by this filter
 242      */
 243     public <D extends Declaration> Collection<D> filter(Collection<D> decls) {
 244         ArrayList<D> res = new ArrayList<D>(decls.size());
 245         for (D d : decls) {
 246             if (matches(d)) {
 247                 res.add(d);
 248             }
 249         }
 250         return res;
 251     }
 252 
 253     /**
 254      * Returns the declarations matched by this filter, with the result
 255      * being restricted to declarations of a given kind.
 256      * Similar to the simpler
 257      * {@linkplain #filter(Collection) single-parameter version}
 258      * of <tt>filter</tt>, but the result type is specified explicitly.
 259      *
 260      * @param <D>      type of the declarations being returned
 261      * @param decls    declarations being filtered
 262      * @param resType  type of the declarations being returned --
 263      *                  the reflective view of <tt>D</tt>
 264      * @return the declarations matched by this filter, restricted to those
 265      *                  of the specified type
 266      */
 267     public <D extends Declaration> Collection<D>
 268             filter(Collection<? extends Declaration> decls, Class<D> resType) {
 269         ArrayList<D> res = new ArrayList<D>(decls.size());
 270         for (Declaration d : decls) {
 271             if (resType.isInstance(d) && matches(d)) {
 272                 res.add(resType.cast(d));
 273             }
 274         }
 275         return res;
 276     }
 277 
 278 
 279 
 280     /*
 281      * A filter based on access modifiers.
 282      */
 283     private static class AccessFilter extends DeclarationFilter {
 284 
 285         // The first access modifier to filter on, or null if we're looking
 286         // for declarations with no access modifiers.
 287         private Modifier mod1 = null;
 288 
 289         // The second access modifier to filter on, or null if none.
 290         private Modifier mod2 = null;
 291 
 292         // Returns a filter that matches declarations with no access
 293         // modifiers.
 294         AccessFilter() {
 295         }
 296 
 297         // Returns a filter that matches m.
 298         AccessFilter(Modifier m) {
 299             mod1 = m;
 300         }
 301 
 302         // Returns a filter that matches either m1 or m2.
 303         AccessFilter(Modifier m1, Modifier m2) {
 304             mod1 = m1;
 305             mod2 = m2;
 306         }
 307 
 308         public boolean matches(Declaration d) {
 309             Collection<Modifier> mods = d.getModifiers();
 310             if (mod1 == null) { // looking for package private
 311                 return !(mods.contains(PUBLIC) ||
 312                          mods.contains(PROTECTED) ||
 313                          mods.contains(PRIVATE));
 314             }
 315             return mods.contains(mod1) &&
 316                    (mod2 == null || mods.contains(mod2));
 317         }
 318     }
 319 }