Home » openjdk-7 » com.sun.tools » javac » model » [javadoc | source]

    1   /*
    2    * Copyright (c) 2005, 2010, 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.tools.javac.model;
   27   
   28   import java.lang.annotation.Annotation;
   29   import java.lang.annotation.Inherited;
   30   import java.util.Map;
   31   import javax.lang.model.SourceVersion;
   32   import javax.lang.model.element;
   33   import javax.lang.model.type.DeclaredType;
   34   import javax.lang.model.util.Elements;
   35   import javax.tools.JavaFileObject;
   36   import com.sun.tools.javac.code;
   37   import com.sun.tools.javac.code.Symbol;
   38   import com.sun.tools.javac.code.TypeTags;
   39   import com.sun.tools.javac.comp.AttrContext;
   40   import com.sun.tools.javac.comp.Enter;
   41   import com.sun.tools.javac.comp.Env;
   42   import com.sun.tools.javac.main.JavaCompiler;
   43   import com.sun.tools.javac.processing.PrintingProcessor;
   44   import com.sun.tools.javac.tree.JCTree;
   45   import com.sun.tools.javac.tree.JCTree;
   46   import com.sun.tools.javac.tree.TreeInfo;
   47   import com.sun.tools.javac.tree.TreeScanner;
   48   import com.sun.tools.javac.util;
   49   import com.sun.tools.javac.util.Name;
   50   
   51   import static javax.lang.model.util.ElementFilter.methodsIn;
   52   
   53   /**
   54    * Utility methods for operating on program elements.
   55    *
   56    * <p><b>This is NOT part of any supported API.
   57    * If you write code that depends on this, you do so at your own
   58    * risk.  This code and its internal interfaces are subject to change
   59    * or deletion without notice.</b></p>
   60    */
   61   public class JavacElements implements Elements {
   62   
   63       private JavaCompiler javaCompiler;
   64       private Symtab syms;
   65       private Names names;
   66       private Types types;
   67       private Enter enter;
   68   
   69       public static JavacElements instance(Context context) {
   70           JavacElements instance = context.get(JavacElements.class);
   71           if (instance == null)
   72               instance = new JavacElements(context);
   73           return instance;
   74       }
   75   
   76       /**
   77        * Public for use only by JavacProcessingEnvironment
   78        */
   79       protected JavacElements(Context context) {
   80           setContext(context);
   81       }
   82   
   83       /**
   84        * Use a new context.  May be called from outside to update
   85        * internal state for a new annotation-processing round.
   86        */
   87       public void setContext(Context context) {
   88           context.put(JavacElements.class, this);
   89           javaCompiler = JavaCompiler.instance(context);
   90           syms = Symtab.instance(context);
   91           names = Names.instance(context);
   92           types = Types.instance(context);
   93           enter = Enter.instance(context);
   94       }
   95   
   96   
   97       /**
   98        * An internal-use utility that creates a reified annotation.
   99        */
  100       public static <A extends Annotation> A getAnnotation(Symbol annotated,
  101                                                            Class<A> annoType) {
  102           if (!annoType.isAnnotation())
  103               throw new IllegalArgumentException("Not an annotation type: "
  104                                                  + annoType);
  105           String name = annoType.getName();
  106           for (Attribute.Compound anno : annotated.getAnnotationMirrors())
  107               if (name.equals(anno.type.tsym.flatName().toString()))
  108                   return AnnotationProxyMaker.generateAnnotation(anno, annoType);
  109           return null;
  110       }
  111   
  112       /**
  113        * An internal-use utility that creates a reified annotation.
  114        * This overloaded version take annotation inheritance into account.
  115        */
  116       public static <A extends Annotation> A getAnnotation(ClassSymbol annotated,
  117                                                            Class<A> annoType) {
  118           boolean inherited = annoType.isAnnotationPresent(Inherited.class);
  119           A result = null;
  120           while (annotated.name != annotated.name.table.names.java_lang_Object) {
  121               result = getAnnotation((Symbol)annotated, annoType);
  122               if (result != null || !inherited)
  123                   break;
  124               Type sup = annotated.getSuperclass();
  125               if (sup.tag != TypeTags.CLASS || sup.isErroneous())
  126                   break;
  127               annotated = (ClassSymbol) sup.tsym;
  128           }
  129           return result;
  130       }
  131   
  132   
  133       public PackageSymbol getPackageElement(CharSequence name) {
  134           String strName = name.toString();
  135           if (strName.equals(""))
  136               return syms.unnamedPackage;
  137           return SourceVersion.isName(strName)
  138               ? nameToSymbol(strName, PackageSymbol.class)
  139               : null;
  140       }
  141   
  142       public ClassSymbol getTypeElement(CharSequence name) {
  143           String strName = name.toString();
  144           return SourceVersion.isName(strName)
  145               ? nameToSymbol(strName, ClassSymbol.class)
  146               : null;
  147       }
  148   
  149       /**
  150        * Returns a symbol given the type's or packages's canonical name,
  151        * or null if the name isn't found.
  152        */
  153       private <S extends Symbol> S nameToSymbol(String nameStr, Class<S> clazz) {
  154           Name name = names.fromString(nameStr);
  155           // First check cache.
  156           Symbol sym = (clazz == ClassSymbol.class)
  157                       ? syms.classes.get(name)
  158                       : syms.packages.get(name);
  159   
  160           try {
  161               if (sym == null)
  162                   sym = javaCompiler.resolveIdent(nameStr);
  163   
  164               sym.complete();
  165   
  166               return (sym.kind != Kinds.ERR &&
  167                       sym.exists() &&
  168                       clazz.isInstance(sym) &&
  169                       name.equals(sym.getQualifiedName()))
  170                   ? clazz.cast(sym)
  171                   : null;
  172           } catch (CompletionFailure e) {
  173               return null;
  174           }
  175       }
  176   
  177       public JavacSourcePosition getSourcePosition(Element e) {
  178           Pair<JCTree, JCCompilationUnit> treeTop = getTreeAndTopLevel(e);
  179           if (treeTop == null)
  180               return null;
  181           JCTree tree = treeTop.fst;
  182           JCCompilationUnit toplevel = treeTop.snd;
  183           JavaFileObject sourcefile = toplevel.sourcefile;
  184           if (sourcefile == null)
  185               return null;
  186           return new JavacSourcePosition(sourcefile, tree.pos, toplevel.lineMap);
  187       }
  188   
  189       public JavacSourcePosition getSourcePosition(Element e, AnnotationMirror a) {
  190           Pair<JCTree, JCCompilationUnit> treeTop = getTreeAndTopLevel(e);
  191           if (treeTop == null)
  192               return null;
  193           JCTree tree = treeTop.fst;
  194           JCCompilationUnit toplevel = treeTop.snd;
  195           JavaFileObject sourcefile = toplevel.sourcefile;
  196           if (sourcefile == null)
  197               return null;
  198   
  199           JCTree annoTree = matchAnnoToTree(a, e, tree);
  200           if (annoTree == null)
  201               return null;
  202           return new JavacSourcePosition(sourcefile, annoTree.pos,
  203                                          toplevel.lineMap);
  204       }
  205   
  206       public JavacSourcePosition getSourcePosition(Element e, AnnotationMirror a,
  207                                               AnnotationValue v) {
  208           // TODO: better accuracy in getSourcePosition(... AnnotationValue)
  209           return getSourcePosition(e, a);
  210       }
  211   
  212       /**
  213        * Returns the tree for an annotation given the annotated element
  214        * and the element's own tree.  Returns null if the tree cannot be found.
  215        */
  216       private JCTree matchAnnoToTree(AnnotationMirror findme,
  217                                      Element e, JCTree tree) {
  218           Symbol sym = cast(Symbol.class, e);
  219           class Vis extends JCTree.Visitor {
  220               List<JCAnnotation> result = null;
  221               public void visitTopLevel(JCCompilationUnit tree) {
  222                   result = tree.packageAnnotations;
  223               }
  224               public void visitClassDef(JCClassDecl tree) {
  225                   result = tree.mods.annotations;
  226               }
  227               public void visitMethodDef(JCMethodDecl tree) {
  228                   result = tree.mods.annotations;
  229               }
  230               public void visitVarDef(JCVariableDecl tree) {
  231                   result = tree.mods.annotations;
  232               }
  233           }
  234           Vis vis = new Vis();
  235           tree.accept(vis);
  236           if (vis.result == null)
  237               return null;
  238           return matchAnnoToTree(cast(Attribute.Compound.class, findme),
  239                                  sym.getAnnotationMirrors(),
  240                                  vis.result);
  241       }
  242   
  243       /**
  244        * Returns the tree for an annotation given a list of annotations
  245        * in which to search (recursively) and their corresponding trees.
  246        * Returns null if the tree cannot be found.
  247        */
  248       private JCTree matchAnnoToTree(Attribute.Compound findme,
  249                                      List<Attribute.Compound> annos,
  250                                      List<JCAnnotation> trees) {
  251           for (Attribute.Compound anno : annos) {
  252               for (JCAnnotation tree : trees) {
  253                   JCTree match = matchAnnoToTree(findme, anno, tree);
  254                   if (match != null)
  255                       return match;
  256               }
  257           }
  258           return null;
  259       }
  260   
  261       /**
  262        * Returns the tree for an annotation given an Attribute to
  263        * search (recursively) and its corresponding tree.
  264        * Returns null if the tree cannot be found.
  265        */
  266       private JCTree matchAnnoToTree(final Attribute.Compound findme,
  267                                      final Attribute attr,
  268                                      final JCTree tree) {
  269           if (attr == findme)
  270               return (tree.type.tsym == findme.type.tsym) ? tree : null;
  271   
  272           class Vis implements Attribute.Visitor {
  273               JCTree result = null;
  274               public void visitConstant(Attribute.Constant value) {
  275               }
  276               public void visitClass(Attribute.Class clazz) {
  277               }
  278               public void visitCompound(Attribute.Compound anno) {
  279                   for (Pair<MethodSymbol, Attribute> pair : anno.values) {
  280                       JCExpression expr = scanForAssign(pair.fst, tree);
  281                       if (expr != null) {
  282                           JCTree match = matchAnnoToTree(findme, pair.snd, expr);
  283                           if (match != null) {
  284                               result = match;
  285                               return;
  286                           }
  287                       }
  288                   }
  289               }
  290               public void visitArray(Attribute.Array array) {
  291                   if (tree.getTag() == JCTree.NEWARRAY &&
  292                           types.elemtype(array.type).tsym == findme.type.tsym) {
  293                       List<JCExpression> elems = ((JCNewArray) tree).elems;
  294                       for (Attribute value : array.values) {
  295                           if (value == findme) {
  296                               result = elems.head;
  297                               return;
  298                           }
  299                           elems = elems.tail;
  300                       }
  301                   }
  302               }
  303               public void visitEnum(Attribute.Enum e) {
  304               }
  305               public void visitError(Attribute.Error e) {
  306               }
  307           }
  308           Vis vis = new Vis();
  309           attr.accept(vis);
  310           return vis.result;
  311       }
  312   
  313       /**
  314        * Scans for a JCAssign node with a LHS matching a given
  315        * symbol, and returns its RHS.  Does not scan nested JCAnnotations.
  316        */
  317       private JCExpression scanForAssign(final MethodSymbol sym,
  318                                          final JCTree tree) {
  319           class TS extends TreeScanner {
  320               JCExpression result = null;
  321               public void scan(JCTree t) {
  322                   if (t != null && result == null)
  323                       t.accept(this);
  324               }
  325               public void visitAnnotation(JCAnnotation t) {
  326                   if (t == tree)
  327                       scan(t.args);
  328               }
  329               public void visitAssign(JCAssign t) {
  330                   if (t.lhs.getTag() == JCTree.IDENT) {
  331                       JCIdent ident = (JCIdent) t.lhs;
  332                       if (ident.sym == sym)
  333                           result = t.rhs;
  334                   }
  335               }
  336           }
  337           TS scanner = new TS();
  338           tree.accept(scanner);
  339           return scanner.result;
  340       }
  341   
  342       /**
  343        * Returns the tree node corresponding to this element, or null
  344        * if none can be found.
  345        */
  346       public JCTree getTree(Element e) {
  347           Pair<JCTree, ?> treeTop = getTreeAndTopLevel(e);
  348           return (treeTop != null) ? treeTop.fst : null;
  349       }
  350   
  351       public String getDocComment(Element e) {
  352           // Our doc comment is contained in a map in our toplevel,
  353           // indexed by our tree.  Find our enter environment, which gives
  354           // us our toplevel.  It also gives us a tree that contains our
  355           // tree:  walk it to find our tree.  This is painful.
  356           Pair<JCTree, JCCompilationUnit> treeTop = getTreeAndTopLevel(e);
  357           if (treeTop == null)
  358               return null;
  359           JCTree tree = treeTop.fst;
  360           JCCompilationUnit toplevel = treeTop.snd;
  361           if (toplevel.docComments == null)
  362               return null;
  363           return toplevel.docComments.get(tree);
  364       }
  365   
  366       public PackageElement getPackageOf(Element e) {
  367           return cast(Symbol.class, e).packge();
  368       }
  369   
  370       public boolean isDeprecated(Element e) {
  371           Symbol sym = cast(Symbol.class, e);
  372           return (sym.flags() & Flags.DEPRECATED) != 0;
  373       }
  374   
  375       public Name getBinaryName(TypeElement type) {
  376           return cast(TypeSymbol.class, type).flatName();
  377       }
  378   
  379       public Map<MethodSymbol, Attribute> getElementValuesWithDefaults(
  380                                                           AnnotationMirror a) {
  381           Attribute.Compound anno = cast(Attribute.Compound.class, a);
  382           DeclaredType annotype = a.getAnnotationType();
  383           Map<MethodSymbol, Attribute> valmap = anno.getElementValues();
  384   
  385           for (ExecutableElement ex :
  386                    methodsIn(annotype.asElement().getEnclosedElements())) {
  387               MethodSymbol meth = (MethodSymbol) ex;
  388               Attribute defaultValue = meth.getDefaultValue();
  389               if (defaultValue != null && !valmap.containsKey(meth)) {
  390                   valmap.put(meth, defaultValue);
  391               }
  392           }
  393           return valmap;
  394       }
  395   
  396       /**
  397        * {@inheritDoc}
  398        */
  399       public FilteredMemberList getAllMembers(TypeElement element) {
  400           Symbol sym = cast(Symbol.class, element);
  401           Scope scope = sym.members().dupUnshared();
  402           List<Type> closure = types.closure(sym.asType());
  403           for (Type t : closure)
  404               addMembers(scope, t);
  405           return new FilteredMemberList(scope);
  406       }
  407       // where
  408           private void addMembers(Scope scope, Type type) {
  409               members:
  410               for (Scope.Entry e = type.asElement().members().elems; e != null; e = e.sibling) {
  411                   Scope.Entry overrider = scope.lookup(e.sym.getSimpleName());
  412                   while (overrider.scope != null) {
  413                       if (overrider.sym.kind == e.sym.kind
  414                           && (overrider.sym.flags() & Flags.SYNTHETIC) == 0)
  415                       {
  416                           if (overrider.sym.getKind() == ElementKind.METHOD
  417                           && overrides((ExecutableElement)overrider.sym, (ExecutableElement)e.sym, (TypeElement)type.asElement())) {
  418                               continue members;
  419                           }
  420                       }
  421                       overrider = overrider.next();
  422                   }
  423                   boolean derived = e.sym.getEnclosingElement() != scope.owner;
  424                   ElementKind kind = e.sym.getKind();
  425                   boolean initializer = kind == ElementKind.CONSTRUCTOR
  426                       || kind == ElementKind.INSTANCE_INIT
  427                       || kind == ElementKind.STATIC_INIT;
  428                   if (!derived || (!initializer && e.sym.isInheritedIn(scope.owner, types)))
  429                       scope.enter(e.sym);
  430               }
  431           }
  432   
  433       /**
  434        * Returns all annotations of an element, whether
  435        * inherited or directly present.
  436        *
  437        * @param e  the element being examined
  438        * @return all annotations of the element
  439        */
  440       public List<Attribute.Compound> getAllAnnotationMirrors(Element e) {
  441           Symbol sym = cast(Symbol.class, e);
  442           List<Attribute.Compound> annos = sym.getAnnotationMirrors();
  443           while (sym.getKind() == ElementKind.CLASS) {
  444               Type sup = ((ClassSymbol) sym).getSuperclass();
  445               if (sup.tag != TypeTags.CLASS || sup.isErroneous() ||
  446                       sup.tsym == syms.objectType.tsym) {
  447                   break;
  448               }
  449               sym = sup.tsym;
  450               List<Attribute.Compound> oldAnnos = annos;
  451               for (Attribute.Compound anno : sym.getAnnotationMirrors()) {
  452                   if (isInherited(anno.type) &&
  453                           !containsAnnoOfType(oldAnnos, anno.type)) {
  454                       annos = annos.prepend(anno);
  455                   }
  456               }
  457           }
  458           return annos;
  459       }
  460   
  461       /**
  462        * Tests whether an annotation type is @Inherited.
  463        */
  464       private boolean isInherited(Type annotype) {
  465           for (Attribute.Compound anno : annotype.tsym.getAnnotationMirrors()) {
  466               if (anno.type.tsym == syms.inheritedType.tsym)
  467                   return true;
  468           }
  469           return false;
  470       }
  471   
  472       /**
  473        * Tests whether a list of annotations contains an annotation
  474        * of a given type.
  475        */
  476       private static boolean containsAnnoOfType(List<Attribute.Compound> annos,
  477                                                 Type type) {
  478           for (Attribute.Compound anno : annos) {
  479               if (anno.type.tsym == type.tsym)
  480                   return true;
  481           }
  482           return false;
  483       }
  484   
  485       public boolean hides(Element hiderEl, Element hideeEl) {
  486           Symbol hider = cast(Symbol.class, hiderEl);
  487           Symbol hidee = cast(Symbol.class, hideeEl);
  488   
  489           // Fields only hide fields; methods only methods; types only types.
  490           // Names must match.  Nothing hides itself (just try it).
  491           if (hider == hidee ||
  492                   hider.kind != hidee.kind ||
  493                   hider.name != hidee.name) {
  494               return false;
  495           }
  496   
  497           // Only static methods can hide other methods.
  498           // Methods only hide methods with matching signatures.
  499           if (hider.kind == Kinds.MTH) {
  500               if (!hider.isStatic() ||
  501                           !types.isSubSignature(hider.type, hidee.type)) {
  502                   return false;
  503               }
  504           }
  505   
  506           // Hider must be in a subclass of hidee's class.
  507           // Note that if M1 hides M2, and M2 hides M3, and M3 is accessible
  508           // in M1's class, then M1 and M2 both hide M3.
  509           ClassSymbol hiderClass = hider.owner.enclClass();
  510           ClassSymbol hideeClass = hidee.owner.enclClass();
  511           if (hiderClass == null || hideeClass == null ||
  512                   !hiderClass.isSubClass(hideeClass, types)) {
  513               return false;
  514           }
  515   
  516           // Hidee must be accessible in hider's class.
  517           // The method isInheritedIn is poorly named:  it checks only access.
  518           return hidee.isInheritedIn(hiderClass, types);
  519       }
  520   
  521       public boolean overrides(ExecutableElement riderEl,
  522                                ExecutableElement rideeEl, TypeElement typeEl) {
  523           MethodSymbol rider = cast(MethodSymbol.class, riderEl);
  524           MethodSymbol ridee = cast(MethodSymbol.class, rideeEl);
  525           ClassSymbol origin = cast(ClassSymbol.class, typeEl);
  526   
  527           return rider.name == ridee.name &&
  528   
  529                  // not reflexive as per JLS
  530                  rider != ridee &&
  531   
  532                  // we don't care if ridee is static, though that wouldn't
  533                  // compile
  534                  !rider.isStatic() &&
  535   
  536                  // Symbol.overrides assumes the following
  537                  ridee.isMemberOf(origin, types) &&
  538   
  539                  // check access and signatures; don't check return types
  540                  rider.overrides(ridee, origin, types, false);
  541       }
  542   
  543       public String getConstantExpression(Object value) {
  544           return Constants.format(value);
  545       }
  546   
  547       /**
  548        * Print a representation of the elements to the given writer in
  549        * the specified order.  The main purpose of this method is for
  550        * diagnostics.  The exact format of the output is <em>not</em>
  551        * specified and is subject to change.
  552        *
  553        * @param w the writer to print the output to
  554        * @param elements the elements to print
  555        */
  556       public void printElements(java.io.Writer w, Element... elements) {
  557           for (Element element : elements)
  558               (new PrintingProcessor.PrintingElementVisitor(w, this)).visit(element).flush();
  559       }
  560   
  561       public Name getName(CharSequence cs) {
  562           return names.fromString(cs.toString());
  563       }
  564   
  565       /**
  566        * Returns the tree node and compilation unit corresponding to this
  567        * element, or null if they can't be found.
  568        */
  569       private Pair<JCTree, JCCompilationUnit> getTreeAndTopLevel(Element e) {
  570           Symbol sym = cast(Symbol.class, e);
  571           Env<AttrContext> enterEnv = getEnterEnv(sym);
  572           if (enterEnv == null)
  573               return null;
  574           JCTree tree = TreeInfo.declarationFor(sym, enterEnv.tree);
  575           if (tree == null || enterEnv.toplevel == null)
  576               return null;
  577           return new Pair<JCTree,JCCompilationUnit>(tree, enterEnv.toplevel);
  578       }
  579   
  580       /**
  581        * Returns the best approximation for the tree node and compilation unit
  582        * corresponding to the given element, annotation and value.
  583        * If the element is null, null is returned.
  584        * If the annotation is null or cannot be found, the tree node and
  585        * compilation unit for the element is returned.
  586        * If the annotation value is null or cannot be found, the tree node and
  587        * compilation unit for the annotation is returned.
  588        */
  589       public Pair<JCTree, JCCompilationUnit> getTreeAndTopLevel(
  590                         Element e, AnnotationMirror a, AnnotationValue v) {
  591           if (e == null)
  592               return null;
  593   
  594           Pair<JCTree, JCCompilationUnit> elemTreeTop = getTreeAndTopLevel(e);
  595           if (elemTreeTop == null)
  596               return null;
  597   
  598           if (a == null)
  599               return elemTreeTop;
  600   
  601           JCTree annoTree = matchAnnoToTree(a, e, elemTreeTop.fst);
  602           if (annoTree == null)
  603               return elemTreeTop;
  604   
  605           // 6388543: if v != null, we should search within annoTree to find
  606           // the tree matching v. For now, we ignore v and return the tree of
  607           // the annotation.
  608           return new Pair<JCTree, JCCompilationUnit>(annoTree, elemTreeTop.snd);
  609       }
  610   
  611       /**
  612        * Returns a symbol's enter environment, or null if it has none.
  613        */
  614       private Env<AttrContext> getEnterEnv(Symbol sym) {
  615           // Get enclosing class of sym, or sym itself if it is a class
  616           // or package.
  617           TypeSymbol ts = (sym.kind != Kinds.PCK)
  618                           ? sym.enclClass()
  619                           : (PackageSymbol) sym;
  620           return (ts != null)
  621                   ? enter.getEnv(ts)
  622                   : null;
  623       }
  624   
  625       /**
  626        * Returns an object cast to the specified type.
  627        * @throws NullPointerException if the object is {@code null}
  628        * @throws IllegalArgumentException if the object is of the wrong type
  629        */
  630       private static <T> T cast(Class<T> clazz, Object o) {
  631           if (! clazz.isInstance(o))
  632               throw new IllegalArgumentException(o.toString());
  633           return clazz.cast(o);
  634       }
  635   }

Home » openjdk-7 » com.sun.tools » javac » model » [javadoc | source]