1 /*
   2  * Copyright (c) 2000, 2015, 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 jdk.javadoc.internal.tool;
  27 
  28 
  29 import java.lang.reflect.Modifier;
  30 import java.util.*;
  31 
  32 import javax.lang.model.element.Element;
  33 import javax.lang.model.element.ExecutableElement;
  34 import javax.lang.model.element.PackageElement;
  35 import javax.lang.model.element.TypeElement;
  36 import javax.lang.model.element.VariableElement;
  37 import javax.lang.model.util.Elements;
  38 import javax.lang.model.util.SimpleElementVisitor9;
  39 import javax.tools.JavaFileManager;
  40 import javax.tools.JavaFileObject;
  41 
  42 import com.sun.source.util.DocTrees;
  43 import com.sun.source.util.TreePath;
  44 import com.sun.tools.javac.api.JavacTrees;
  45 import com.sun.tools.javac.code.ClassFinder;
  46 import com.sun.tools.javac.code.Flags;
  47 import com.sun.tools.javac.code.Kinds.Kind;
  48 import com.sun.tools.javac.code.Source;
  49 import com.sun.tools.javac.code.Symbol;
  50 import com.sun.tools.javac.code.Symbol.ClassSymbol;
  51 import com.sun.tools.javac.code.Symbol.CompletionFailure;
  52 import com.sun.tools.javac.code.Symbol.MethodSymbol;
  53 import com.sun.tools.javac.code.Symbol.PackageSymbol;
  54 import com.sun.tools.javac.code.Symbol.VarSymbol;
  55 import com.sun.tools.javac.code.Symtab;
  56 import com.sun.tools.javac.comp.AttrContext;
  57 import com.sun.tools.javac.comp.Check;
  58 import com.sun.tools.javac.comp.Enter;
  59 import com.sun.tools.javac.comp.Env;
  60 import com.sun.tools.javac.file.JavacFileManager;
  61 import com.sun.tools.javac.model.JavacElements;
  62 import com.sun.tools.javac.model.JavacTypes;
  63 import com.sun.tools.javac.tree.JCTree;
  64 import com.sun.tools.javac.tree.JCTree.JCClassDecl;
  65 import com.sun.tools.javac.tree.JCTree.JCCompilationUnit;
  66 import com.sun.tools.javac.tree.JCTree.JCPackageDecl;
  67 import com.sun.tools.javac.util.Context;
  68 import com.sun.tools.javac.util.DefinedBy;
  69 import com.sun.tools.javac.util.DefinedBy.Api;
  70 import com.sun.tools.javac.util.Names;
  71 
  72 import static com.sun.tools.javac.code.Scope.LookupKind.NON_RECURSIVE;
  73 
  74 /**
  75  * Holds the environment for a run of javadoc.
  76  * Holds only the information needed throughout the
  77  * run and not the compiler info that could be GC'ed
  78  * or ported.
  79  *
  80  *  <p><b>This is NOT part of any supported API.
  81  *  If you write code that depends on this, you do so at your own risk.
  82  *  This code and its internal interfaces are subject to change or
  83  *  deletion without notice.</b>
  84  *
  85  * @since 1.4
  86  * @author Robert Field
  87  * @author Neal Gafter (rewrite)
  88  * @author Scott Seligman (generics)
  89  */
  90 public class DocEnv {
  91     protected static final Context.Key<DocEnv> docEnvKey = new Context.Key<>();
  92 
  93     public static DocEnv instance(Context context) {
  94         DocEnv instance = context.get(docEnvKey);
  95         if (instance == null)
  96             instance = new DocEnv(context);
  97         return instance;
  98     }
  99 
 100     private final Messager messager;
 101 
 102     /** Predefined symbols known to the compiler. */
 103     public final Symtab syms;
 104 
 105     /** Referenced directly in RootDocImpl. */
 106     private final ClassFinder finder;
 107 
 108     /** Javadoc's own version of the compiler's enter phase. */
 109     final Enter enter;
 110 
 111     /** The name table. */
 112     private Names names;
 113 
 114     /** The encoding name. */
 115     private String encoding;
 116 
 117     final Symbol externalizableSym;
 118 
 119     /** Access filter (public, protected, ...).  */
 120     protected ModifierFilter filter;
 121 
 122     /**
 123      * True if we do not want to print any notifications at all.
 124      */
 125     boolean quiet = false;
 126 
 127     Check chk;
 128     com.sun.tools.javac.code.Types types;
 129     JavaFileManager fileManager;
 130     public final Context context;
 131 
 132     WeakHashMap<JCTree, TreePath> treePaths = new WeakHashMap<>();
 133 
 134     public final HashMap<PackageElement, JavaFileObject> pkgToJavaFOMap = new HashMap<>();
 135 
 136     /** Allow documenting from class files? */
 137     boolean docClasses = false;
 138 
 139     /**
 140      * The source language version.
 141      */
 142     public final Source source;
 143 
 144     public final Elements elements;
 145 
 146     public final JavacTypes typeutils;
 147 
 148     protected RootDocImpl root;
 149 
 150     public final DocTrees docTrees;
 151 
 152     public final Map<Element, TreePath> elementToTreePath;
 153 
 154     /**
 155      * Constructor
 156      *
 157      * @param context      Context for this javadoc instance.
 158      */
 159     protected DocEnv(Context context) {
 160         context.put(docEnvKey, this);
 161         this.context = context;
 162 
 163         messager = Messager.instance0(context);
 164         syms = Symtab.instance(context);
 165         finder = JavadocClassFinder.instance(context);
 166         enter = JavadocEnter.instance(context);
 167         names = Names.instance(context);
 168         externalizableSym = syms.enterClass(names.fromString("java.io.Externalizable"));
 169         chk = Check.instance(context);
 170         types = com.sun.tools.javac.code.Types.instance(context);
 171         fileManager = context.get(JavaFileManager.class);
 172         if (fileManager instanceof JavacFileManager) {
 173             ((JavacFileManager)fileManager).setSymbolFileEnabled(false);
 174         }
 175         docTrees = JavacTrees.instance(context);
 176         source = Source.instance(context);
 177         elements =  JavacElements.instance(context);
 178         typeutils = JavacTypes.instance(context);
 179         elementToTreePath = new HashMap<>();
 180     }
 181 
 182     public void intialize(String encoding,
 183             String showAccess,
 184             String overviewpath,
 185             List<String> javaNames,
 186             Iterable<? extends JavaFileObject> fileObjects,
 187             List<String> subPackages,
 188             List<String> excludedPackages,
 189             boolean docClasses,
 190             boolean quiet) {
 191         this.filter = ModifierFilter.getModifierFilter(showAccess);
 192         this.quiet = quiet;
 193 
 194         this.setEncoding(encoding);
 195         this.docClasses = docClasses;
 196     }
 197 
 198     /**
 199      * Load a class by qualified name.
 200      */
 201     public TypeElement loadClass(String name) {
 202         try {
 203             ClassSymbol c = finder.loadClass(names.fromString(name));
 204             return c;
 205         } catch (CompletionFailure ex) {
 206             chk.completionError(null, ex);
 207             return null;
 208         }
 209     }
 210 
 211     private boolean isSynthetic(long flags) {
 212         return (flags & Flags.SYNTHETIC) != 0;
 213     }
 214 
 215     private boolean isSynthetic(Symbol sym) {
 216         return isSynthetic(sym.flags_field);
 217     }
 218 
 219     SimpleElementVisitor9<Boolean, Void> shouldDocumentVisitor = null;
 220     public boolean shouldDocument(Element e) {
 221         if (shouldDocumentVisitor == null) {
 222             shouldDocumentVisitor = new SimpleElementVisitor9<Boolean, Void>() {
 223 
 224             @Override @DefinedBy(Api.LANGUAGE_MODEL)
 225             public Boolean visitType(TypeElement e, Void p) {
 226                 return shouldDocument((ClassSymbol)e);
 227             }
 228 
 229             @Override @DefinedBy(Api.LANGUAGE_MODEL)
 230             public Boolean visitVariable(VariableElement e, Void p) {
 231                 return shouldDocument((VarSymbol)e);
 232             }
 233 
 234             @Override @DefinedBy(Api.LANGUAGE_MODEL)
 235             public Boolean visitExecutable(ExecutableElement e, Void p) {
 236                 return shouldDocument((MethodSymbol)e);
 237             }
 238         };
 239         }
 240         return shouldDocumentVisitor.visit(e);
 241     }
 242 
 243     /** Check whether this member should be documented. */
 244     public boolean shouldDocument(VarSymbol sym) {
 245         long mod = sym.flags();
 246         if (isSynthetic(mod)) {
 247             return false;
 248         }
 249         return filter.checkModifier(translateModifiers(mod));
 250     }
 251 
 252     /** Check whether this member should be documented. */
 253     public boolean shouldDocument(MethodSymbol sym) {
 254         long mod = sym.flags();
 255         if (isSynthetic(mod)) {
 256             return false;
 257         }
 258         return filter.checkModifier(translateModifiers(mod));
 259     }
 260 
 261     void setElementToTreePath(Element e, TreePath tree) {
 262         if (e == null || tree == null)
 263             return;
 264         elementToTreePath.put(e, tree);
 265     }
 266 
 267     private boolean hasLeaf(ClassSymbol sym) {
 268         TreePath path = elementToTreePath.get(sym);
 269         if (path == null)
 270             return false;
 271         return path.getLeaf() != null;
 272     }
 273 
 274     /** check whether this class should be documented. */
 275     public boolean shouldDocument(ClassSymbol sym) {
 276         return
 277             !isSynthetic(sym.flags_field) && // no synthetics
 278             (docClasses || hasLeaf(sym)) &&
 279             isVisible(sym);
 280     }
 281 
 282     //### Comment below is inaccurate wrt modifier filter testing
 283     /**
 284      * Check the visibility if this is an nested class.
 285      * if this is not a nested class, return true.
 286      * if this is an static visible nested class,
 287      *    return true.
 288      * if this is an visible nested class
 289      *    if the outer class is visible return true.
 290      *    else return false.
 291      * IMPORTANT: This also allows, static nested classes
 292      * to be defined inside an nested class, which is not
 293      * allowed by the compiler. So such an test case will
 294      * not reach upto this method itself, but if compiler
 295      * allows it, then that will go through.
 296      */
 297     public boolean isVisible(ClassSymbol sym) {
 298         long mod = sym.flags_field;
 299         if (!filter.checkModifier(translateModifiers(mod))) {
 300             return false;
 301         }
 302         ClassSymbol encl = sym.owner.enclClass();
 303         return (encl == null || (mod & Flags.STATIC) != 0 || isVisible(encl));
 304     }
 305 
 306     //---------------- print forwarders ----------------//
 307 
 308     // ERRORS
 309     /**
 310      * Print error message, increment error count.
 311      *
 312      * @param msg message to print.
 313      */
 314     public void printError(String msg) {
 315         messager.printError(msg);
 316     }
 317 
 318 //    /**
 319 //     * Print error message, increment error count.
 320 //     *
 321 //     * @param key selects message from resource
 322 //     */
 323 //    public void error(Element element, String key) {
 324 //        if (element == null)
 325 //            messager.error(key);
 326 //        else
 327 //            messager.error(element, key);
 328 //    }
 329 //
 330 //    public void error(String prefix, String key) {
 331 //        printError(prefix + ":" + messager.getText(key));
 332 //    }
 333 //
 334 //    /**
 335 //     * Print error message, increment error count.
 336 //     *
 337 //     * @param path the path to the source
 338 //     * @param key selects message from resource
 339 //     */
 340 //    public void error(DocTreePath path, String key) {
 341 //        messager.error(path, key);
 342 //    }
 343 //
 344 //    /**
 345 //     * Print error message, increment error count.
 346 //     *
 347 //     * @param path the path to the source
 348 //     * @param msg message to print.
 349 //     */
 350 //    public void printError(DocTreePath path, String msg) {
 351 //        messager.printError(path, msg);
 352 //    }
 353 //
 354 //    /**
 355 //     * Print error message, increment error count.
 356 //     * @param e the target element
 357 //     * @param msg message to print.
 358 //     */
 359 //    public void printError(Element e, String msg) {
 360 //        messager.printError(e, msg);
 361 //    }
 362 
 363     /**
 364      * Print error message, increment error count.
 365      *
 366      * @param element the source element
 367      * @param key selects message from resource
 368      * @param args replacement arguments
 369      */
 370     public void error(Element element, String key, String... args) {
 371         if (element == null)
 372             messager.error(key, (Object[]) args);
 373         else
 374             messager.error(element, key, (Object[]) args);
 375     }
 376 
 377     // WARNINGS
 378 
 379 //    /**
 380 //     * Print warning message, increment warning count.
 381 //     *
 382 //     * @param msg message to print.
 383 //     */
 384 //    public void printWarning(String msg) {
 385 //        messager.printWarning(msg);
 386 //    }
 387 //
 388 //    public void warning(String key) {
 389 //        warning((Element)null, key);
 390 //    }
 391 
 392     public void warning(String key, String... args) {
 393         warning((Element)null, key, args);
 394     }
 395 
 396 //    /**
 397 //     * Print warning message, increment warning count.
 398 //     *
 399 //     * @param element the source element
 400 //     * @param key selects message from resource
 401 //     */
 402 //    public void warning(Element element, String key) {
 403 //        if (element == null)
 404 //            messager.warning(key);
 405 //        else
 406 //            messager.warning(element, key);
 407 //    }
 408 //
 409 //    /**
 410 //     * Print warning message, increment warning count.
 411 //     *
 412 //     * @param path the path to the source
 413 //     * @param msg message to print.
 414 //     */
 415 //    public void printWarning(DocTreePath path, String msg) {
 416 //        messager.printWarning(path, msg);
 417 //    }
 418 //
 419 //    /**
 420 //     * Print warning message, increment warning count.
 421 //     *
 422 //     * @param e  the source element
 423 //     * @param msg message to print.
 424 //     */
 425 //    public void printWarning(Element e, String msg) {
 426 //        messager.printWarning(e, msg);
 427 //    }
 428 
 429     /**
 430      * Print warning message, increment warning count.
 431      *
 432      * @param e    the source element
 433      * @param key  selects message from resource
 434      * @param args the replace arguments
 435      */
 436     public void warning(Element e, String key, String... args) {
 437         if (e == null)
 438             messager.warning(key, (Object[]) args);
 439         else
 440             messager.warning(e, key, (Object[]) args);
 441     }
 442 
 443 //    Note: no longer required
 444 //    /**
 445 //     * Print a message.
 446 //     *
 447 //     * @param msg message to print.
 448 //     */
 449 //    public void printNotice(String msg) {
 450 //        if (quiet) {
 451 //            return;
 452 //        }
 453 //        messager.printNotice(msg);
 454 //    }
 455 
 456 //  Note: no longer required
 457 //    /**
 458 //     * Print a message.
 459 //     *
 460 //     * @param e the source element
 461 //     * @param msg message to print.
 462 //     */
 463 //    public void printNotice(Element e, String msg) {
 464 //        if (quiet) {
 465 //            return;
 466 //        }
 467 //        messager.printNotice(e, msg);
 468 //    }
 469 
 470     //  NOTICES
 471     /**
 472      * Print a message.
 473      *
 474      * @param key selects message from resource
 475      */
 476     public void notice(String key) {
 477         if (quiet) {
 478             return;
 479         }
 480         messager.notice(key);
 481     }
 482 
 483 //    Note: not used anymore
 484 //    /**
 485 //     * Print a message.
 486 //     *
 487 //     * @param path the path to the source
 488 //     * @param msg message to print.
 489 //     */
 490 //    public void printNotice(DocTreePath path, String msg) {
 491 //        if (quiet) {
 492 //            return;
 493 //        }
 494 //        messager.printNotice(path, msg);
 495 //    }
 496 
 497     /**
 498      * Print a message.
 499      *
 500      * @param key selects message from resource
 501      * @param a1 first argument
 502      */
 503     public void notice(String key, String a1) {
 504         if (quiet) {
 505             return;
 506         }
 507         messager.notice(key, a1);
 508     }
 509 
 510 //    Note: not used anymore
 511 //    /**
 512 //     * Print a message.
 513 //     *
 514 //     * @param key selects message from resource
 515 //     * @param a1 first argument
 516 //     * @param a2 second argument
 517 //     */
 518 //    public void notice(String key, String a1, String a2) {
 519 //        if (quiet) {
 520 //            return;
 521 //        }
 522 //        messager.notice(key, a1, a2);
 523 //    }
 524 //
 525 
 526 //    Note: not used anymore
 527 //    /**
 528 //     * Print a message.
 529 //     *
 530 //     * @param key selects message from resource
 531 //     * @param a1 first argument
 532 //     * @param a2 second argument
 533 //     * @param a3 third argument
 534 //     */
 535 //    public void notice(String key, String a1, String a2, String a3) {
 536 //        if (quiet) {
 537 //            return;
 538 //        }
 539 //        messager.notice(key, a1, a2, a3);
 540 //    }
 541 
 542     /**
 543      * Exit, reporting errors and warnings.
 544      */
 545     public void exit() {
 546         // Messager should be replaced by a more general
 547         // compilation environment.  This can probably
 548         // subsume DocEnv as well.
 549         messager.exit();
 550     }
 551 
 552     /**
 553      * Adds all inner classes of this class, and their inner classes recursively, to the list
 554      */
 555     void addAllClasses(Collection<TypeElement> list, TypeElement typeElement, boolean filtered) {
 556         ClassSymbol klass = (ClassSymbol)typeElement;
 557         try {
 558             if (isSynthetic(klass.flags())) return;
 559             // sometimes synthetic classes are not marked synthetic
 560             if (!JavadocTool.isValidClassName(klass.name.toString())) return;
 561             if (filtered && !shouldDocument(klass)) return;
 562             if (list.contains(klass)) return;
 563             list.add(klass);
 564             for (Symbol sym : klass.members().getSymbols(NON_RECURSIVE)) {
 565                 if (sym != null && sym.kind == Kind.TYP) {
 566                     ClassSymbol s = (ClassSymbol)sym;
 567                     if (!isSynthetic(s.flags())) {
 568                         addAllClasses(list, s, filtered);
 569                     }
 570                 }
 571             }
 572         } catch (CompletionFailure e) {
 573             // quietly ignore completion failures
 574         }
 575     }
 576 
 577     /**
 578      * Return a list of all classes contained in this package, including
 579      * member classes of those classes, and their member classes, etc.
 580      */
 581     void addAllClasses(Collection<TypeElement> list, PackageElement pkg) {
 582         boolean filtered = true;
 583         PackageSymbol sym = (PackageSymbol)pkg;
 584         for (Symbol isym : sym.members().getSymbols(NON_RECURSIVE)) {
 585             if (isym != null) {
 586                 ClassSymbol s = (ClassSymbol)isym;
 587                 if (!isSynthetic(s)) {
 588                     addAllClasses(list, s, filtered);
 589                 }
 590             }
 591         }
 592     }
 593 
 594     TreePath getTreePath(JCCompilationUnit tree) {
 595         TreePath p = treePaths.get(tree);
 596         if (p == null)
 597             treePaths.put(tree, p = new TreePath(tree));
 598         return p;
 599     }
 600 
 601     TreePath getTreePath(JCCompilationUnit toplevel, JCPackageDecl tree) {
 602         TreePath p = treePaths.get(tree);
 603         if (p == null)
 604             treePaths.put(tree, p = new TreePath(getTreePath(toplevel), tree));
 605         return p;
 606     }
 607 
 608     TreePath getTreePath(JCCompilationUnit toplevel, JCClassDecl tree) {
 609         TreePath p = treePaths.get(tree);
 610         if (p == null)
 611             treePaths.put(tree, p = new TreePath(getTreePath(toplevel), tree));
 612         return p;
 613     }
 614 
 615     TreePath getTreePath(JCCompilationUnit toplevel, JCClassDecl cdecl, JCTree tree) {
 616         return new TreePath(getTreePath(toplevel, cdecl), tree);
 617     }
 618 
 619     public com.sun.tools.javac.code.Types getTypes() {
 620         return types;
 621     }
 622 
 623     /**
 624      * Set the encoding.
 625      */
 626     public void setEncoding(String encoding) {
 627         this.encoding = encoding;
 628     }
 629 
 630     public Env<AttrContext> getEnv(ClassSymbol tsym) {
 631         return enter.getEnv(tsym);
 632     }
 633 
 634     /**
 635      * Get the encoding.
 636      */
 637     public String getEncoding() {
 638         return encoding;
 639     }
 640 
 641     /**
 642      * Convert modifier bits from private coding used by
 643      * the compiler to that of java.lang.reflect.Modifier.
 644      */
 645     static int translateModifiers(long flags) {
 646         int result = 0;
 647         if ((flags & Flags.ABSTRACT) != 0)
 648             result |= Modifier.ABSTRACT;
 649         if ((flags & Flags.FINAL) != 0)
 650             result |= Modifier.FINAL;
 651         if ((flags & Flags.INTERFACE) != 0)
 652             result |= Modifier.INTERFACE;
 653         if ((flags & Flags.NATIVE) != 0)
 654             result |= Modifier.NATIVE;
 655         if ((flags & Flags.PRIVATE) != 0)
 656             result |= Modifier.PRIVATE;
 657         if ((flags & Flags.PROTECTED) != 0)
 658             result |= Modifier.PROTECTED;
 659         if ((flags & Flags.PUBLIC) != 0)
 660             result |= Modifier.PUBLIC;
 661         if ((flags & Flags.STATIC) != 0)
 662             result |= Modifier.STATIC;
 663         if ((flags & Flags.SYNCHRONIZED) != 0)
 664             result |= Modifier.SYNCHRONIZED;
 665         if ((flags & Flags.TRANSIENT) != 0)
 666             result |= Modifier.TRANSIENT;
 667         if ((flags & Flags.VOLATILE) != 0)
 668             result |= Modifier.VOLATILE;
 669         return result;
 670     }
 671 
 672     private final Set<Element> includedSet = new HashSet<>();
 673 
 674     public void setIncluded(Element element) {
 675         includedSet.add(element);
 676     }
 677 
 678     private SimpleElementVisitor9<Boolean, Void> includedVisitor = null;
 679 
 680     public boolean isIncluded(Element e) {
 681         if (e == null) {
 682             return false;
 683         }
 684         if (includedVisitor == null) {
 685             includedVisitor = new SimpleElementVisitor9<Boolean, Void>() {
 686                 @Override @DefinedBy(Api.LANGUAGE_MODEL)
 687                 public Boolean visitType(TypeElement e, Void p) {
 688                     if (includedSet.contains(e)) {
 689                         return true;
 690                     }
 691                     if (shouldDocument(e)) {
 692                         // Class is nameable from top-level and
 693                         // the class and all enclosing classes
 694                         // pass the modifier filter.
 695                         PackageElement pkg = elements.getPackageOf(e);
 696                         if (includedSet.contains(pkg)) {
 697                             setIncluded(e);
 698                             return true;
 699                         }
 700                         Element enclosing = e.getEnclosingElement();
 701                         if (enclosing != null && includedSet.contains(enclosing)) {
 702                             setIncluded(e);
 703                             return true;
 704                         }
 705                     }
 706                     return false;
 707                 }
 708 
 709                 @Override @DefinedBy(Api.LANGUAGE_MODEL)
 710                 public Boolean defaultAction(Element e, Void p) {
 711                     if (includedSet.contains(e) || shouldDocument(e)) {
 712                         return true;
 713                     }
 714                     return false;
 715                 }
 716 
 717                 @Override @DefinedBy(Api.LANGUAGE_MODEL)
 718                 public Boolean visitPackage(PackageElement e, Void p) {
 719                     return includedSet.contains(e);
 720                 }
 721 
 722                 @Override @DefinedBy(Api.LANGUAGE_MODEL)
 723                 public Boolean visitUnknown(Element e, Void p) {
 724                     throw new AssertionError("got element: " + e);
 725                 }
 726             };
 727         }
 728         return includedVisitor.visit(e);
 729     }
 730 
 731     public boolean isQuiet() {
 732         return quiet;
 733     }
 734 
 735     /**
 736      * A class which filters the access flags on classes, fields, methods, etc.
 737      *
 738      * <p>
 739      * <b>This is NOT part of any supported API. If you write code that depends on this, you do so
 740      * at your own risk. This code and its internal interfaces are subject to change or deletion
 741      * without notice.</b>
 742      *
 743      * @see javax.lang.model.element.Modifier
 744      * @author Robert Field
 745      */
 746 
 747     private static class ModifierFilter {
 748 
 749         static enum FilterFlag {
 750             PACKAGE,
 751             PRIVATE,
 752             PROTECTED,
 753             PUBLIC
 754         }
 755 
 756         private Set<FilterFlag> oneOf;
 757 
 758         /**
 759          * Constructor - Specify a filter.
 760          *
 761          * @param oneOf a set containing desired flags to be matched.
 762          */
 763         ModifierFilter(Set<FilterFlag> oneOf) {
 764             this.oneOf = oneOf;
 765         }
 766 
 767         /**
 768          * Constructor - Specify a filter.
 769          *
 770          * @param oneOf an array containing desired flags to be matched.
 771          */
 772         ModifierFilter(FilterFlag... oneOf) {
 773             this.oneOf = new HashSet<>();
 774             this.oneOf.addAll(Arrays.asList(oneOf));
 775         }
 776 
 777         static ModifierFilter getModifierFilter(String showAccess) {
 778             switch (showAccess) {
 779                 case "public":
 780                     return new ModifierFilter(FilterFlag.PUBLIC);
 781                 case "package":
 782                     return new ModifierFilter(FilterFlag.PUBLIC, FilterFlag.PROTECTED,
 783                                               FilterFlag.PACKAGE);
 784                 case "private":
 785                     return new ModifierFilter(FilterFlag.PRIVATE);
 786                 default:
 787                     return new ModifierFilter(FilterFlag.PUBLIC, FilterFlag.PROTECTED);
 788             }
 789         }
 790 
 791         private boolean hasFlag(long flag, long modifierBits) {
 792             return (flag & modifierBits) != 0;
 793         }
 794 
 795         private List<FilterFlag> flagsToModifiers(long modifierBits) {
 796             List<FilterFlag> list = new ArrayList<>();
 797             boolean isPackage = true;
 798             if (hasFlag(com.sun.tools.javac.code.Flags.PRIVATE, modifierBits)) {
 799                 list.add(FilterFlag.PRIVATE);
 800                 isPackage = false;
 801             }
 802             if (hasFlag(com.sun.tools.javac.code.Flags.PROTECTED, modifierBits)) {
 803                 list.add(FilterFlag.PROTECTED);
 804                 isPackage = false;
 805             }
 806             if (hasFlag(com.sun.tools.javac.code.Flags.PUBLIC, modifierBits)) {
 807                 list.add(FilterFlag.PUBLIC);
 808                 isPackage = false;
 809             }
 810             if (isPackage) {
 811                 list.add(FilterFlag.PACKAGE);
 812             }
 813             return list;
 814         }
 815 
 816         /**
 817          * Filter on modifier bits.
 818          *
 819          * @param modifierBits Bits as specified in the Modifier class
 820          *
 821          * @return Whether the modifierBits pass this filter.
 822          */
 823         public boolean checkModifier(int modifierBits) {
 824             return checkModifier(flagsToModifiers(modifierBits));
 825         }
 826 
 827         /**
 828          * Filter on Filter flags
 829          *
 830          * @param modifiers Flags as specified in the FilterFlags enumeration.
 831          *
 832          * @return if the modifier is contained.
 833          */
 834         public boolean checkModifier(List<FilterFlag> modifiers) {
 835             if (oneOf.contains(FilterFlag.PRIVATE)) {
 836                 return true;
 837             }
 838             for (FilterFlag mod : modifiers) {
 839                 if (oneOf.contains(mod)) {
 840                     return true;
 841                 }
 842             }
 843             return false;
 844         }
 845 
 846     } // end ModifierFilter
 847 }