001: /*
002: * Copyright 2005-2006 Sun Microsystems, Inc. All Rights Reserved.
003: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004: *
005: * This code is free software; you can redistribute it and/or modify it
006: * under the terms of the GNU General Public License version 2 only, as
007: * published by the Free Software Foundation. Sun designates this
008: * particular file as subject to the "Classpath" exception as provided
009: * by Sun in the LICENSE file that accompanied this code.
010: *
011: * This code is distributed in the hope that it will be useful, but WITHOUT
012: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
014: * version 2 for more details (a copy is included in the LICENSE file that
015: * accompanied this code).
016: *
017: * You should have received a copy of the GNU General Public License version
018: * 2 along with this work; if not, write to the Free Software Foundation,
019: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020: *
021: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022: * CA 95054 USA or visit www.sun.com if you need additional information or
023: * have any questions.
024: */
025:
026: package com.sun.tools.javac.model;
027:
028: import java.lang.annotation.Annotation;
029: import java.lang.annotation.Inherited;
030: import java.util.Map;
031: import javax.lang.model.SourceVersion;
032: import javax.lang.model.element.*;
033: import javax.lang.model.type.DeclaredType;
034: import javax.lang.model.util.Elements;
035: import javax.tools.JavaFileObject;
036: import com.sun.tools.javac.code.*;
037: import com.sun.tools.javac.code.Symbol.*;
038: import com.sun.tools.javac.code.TypeTags;
039: import com.sun.tools.javac.comp.AttrContext;
040: import com.sun.tools.javac.comp.Enter;
041: import com.sun.tools.javac.comp.Env;
042: import com.sun.tools.javac.jvm.ClassReader;
043: import com.sun.tools.javac.main.JavaCompiler;
044: import com.sun.tools.javac.processing.PrintingProcessor;
045: import com.sun.tools.javac.tree.JCTree;
046: import com.sun.tools.javac.tree.JCTree.*;
047: import com.sun.tools.javac.tree.TreeInfo;
048: import com.sun.tools.javac.tree.TreeScanner;
049: import com.sun.tools.javac.util.Name;
050: import com.sun.tools.javac.util.*;
051:
052: import static javax.lang.model.util.ElementFilter.methodsIn;
053:
054: /**
055: * Utility methods for operating on program elements.
056: *
057: * <p><b>This is NOT part of any API supported by Sun Microsystems.
058: * If you write code that depends on this, you do so at your own
059: * risk. This code and its internal interfaces are subject to change
060: * or deletion without notice.</b></p>
061: */
062: @Version("@(#)JavacElements.java 1.20 07/06/14")
063: public class JavacElements implements Elements {
064:
065: private JavaCompiler javaCompiler;
066: private Symtab syms;
067: private Name.Table names;
068: private Types types;
069: private Enter enter;
070: private ClassReader reader;
071:
072: private static final Context.Key<JavacElements> KEY = new Context.Key<JavacElements>();
073:
074: public static JavacElements instance(Context context) {
075: JavacElements instance = context.get(KEY);
076: if (instance == null) {
077: instance = new JavacElements(context);
078: context.put(KEY, instance);
079: }
080: return instance;
081: }
082:
083: /**
084: * Public for use only by JavacProcessingEnvironment
085: */
086: // TODO JavacElements constructor should be protected
087: public JavacElements(Context context) {
088: setContext(context);
089: }
090:
091: /**
092: * Use a new context. May be called from outside to update
093: * internal state for a new annotation-processing round.
094: * This instance is *not* then registered with the new context.
095: */
096: public void setContext(Context context) {
097: javaCompiler = JavaCompiler.instance(context);
098: syms = Symtab.instance(context);
099: names = Name.Table.instance(context);
100: types = Types.instance(context);
101: enter = Enter.instance(context);
102: reader = ClassReader.instance(context);
103: }
104:
105: /**
106: * An internal-use utility that creates a reified annotation.
107: */
108: public static <A extends Annotation> A getAnnotation(
109: Symbol annotated, Class<A> annoType) {
110: if (!annoType.isAnnotation())
111: throw new IllegalArgumentException(
112: "Not an annotation type: " + annoType);
113: String name = annoType.getName();
114: for (Attribute.Compound anno : annotated.getAnnotationMirrors())
115: if (name.equals(anno.type.tsym.flatName().toString()))
116: return AnnotationProxyMaker.generateAnnotation(anno,
117: annoType);
118: return null;
119: }
120:
121: /**
122: * An internal-use utility that creates a reified annotation.
123: * This overloaded version take annotation inheritance into account.
124: */
125: public static <A extends Annotation> A getAnnotation(
126: ClassSymbol annotated, Class<A> annoType) {
127: boolean inherited = annoType
128: .isAnnotationPresent(Inherited.class);
129: A result = null;
130: while (annotated.name != annotated.name.table.java_lang_Object) {
131: result = getAnnotation((Symbol) annotated, annoType);
132: if (result != null || !inherited)
133: break;
134: Type sup = annotated.getSuperclass();
135: if (sup.tag != TypeTags.CLASS || sup.isErroneous())
136: break;
137: annotated = (ClassSymbol) sup.tsym;
138: }
139: return result;
140: }
141:
142: public PackageSymbol getPackageElement(CharSequence name) {
143: String strName = name.toString();
144: if (strName.equals(""))
145: return syms.unnamedPackage;
146: return SourceVersion.isName(strName) ? nameToSymbol(strName,
147: PackageSymbol.class) : null;
148: }
149:
150: public ClassSymbol getTypeElement(CharSequence name) {
151: String strName = name.toString();
152: return SourceVersion.isName(strName) ? nameToSymbol(strName,
153: ClassSymbol.class) : null;
154: }
155:
156: /**
157: * Returns a symbol given the type's or packages's canonical name,
158: * or null if the name isn't found.
159: */
160: private <S extends Symbol> S nameToSymbol(String nameStr,
161: Class<S> clazz) {
162: Name name = names.fromString(nameStr);
163: // First check cache.
164: Symbol sym = (clazz == ClassSymbol.class) ? syms.classes
165: .get(name) : syms.packages.get(name);
166:
167: try {
168: if (sym == null)
169: sym = javaCompiler.resolveIdent(nameStr);
170:
171: sym.complete();
172:
173: return (sym.kind != Kinds.ERR && sym.exists()
174: && clazz.isInstance(sym) && name.equals(sym
175: .getQualifiedName())) ? clazz.cast(sym) : null;
176: } catch (CompletionFailure e) {
177: return null;
178: }
179: }
180:
181: public JavacSourcePosition getSourcePosition(Element e) {
182: Pair<JCTree, JCCompilationUnit> treeTop = getTreeAndTopLevel(e);
183: if (treeTop == null)
184: return null;
185: JCTree tree = treeTop.fst;
186: JCCompilationUnit toplevel = treeTop.snd;
187: JavaFileObject sourcefile = toplevel.sourcefile;
188: if (sourcefile == null)
189: return null;
190: return new JavacSourcePosition(sourcefile, tree.pos,
191: toplevel.lineMap);
192: }
193:
194: public JavacSourcePosition getSourcePosition(Element e,
195: AnnotationMirror a) {
196: Pair<JCTree, JCCompilationUnit> treeTop = getTreeAndTopLevel(e);
197: if (treeTop == null)
198: return null;
199: JCTree tree = treeTop.fst;
200: JCCompilationUnit toplevel = treeTop.snd;
201: JavaFileObject sourcefile = toplevel.sourcefile;
202: if (sourcefile == null)
203: return null;
204:
205: JCTree annoTree = matchAnnoToTree(a, e, tree);
206: if (annoTree == null)
207: return null;
208: return new JavacSourcePosition(sourcefile, annoTree.pos,
209: toplevel.lineMap);
210: }
211:
212: public JavacSourcePosition getSourcePosition(Element e,
213: AnnotationMirror a, AnnotationValue v) {
214: // TODO: better accuracy in getSourcePosition(... AnnotationValue)
215: return getSourcePosition(e, a);
216: }
217:
218: /**
219: * Returns the tree for an annotation given the annotated element
220: * and the element's own tree. Returns null if the tree cannot be found.
221: */
222: private JCTree matchAnnoToTree(AnnotationMirror findme, Element e,
223: JCTree tree) {
224: Symbol sym = cast(Symbol.class, e);
225: class Vis extends JCTree.Visitor {
226: List<JCAnnotation> result = null;
227:
228: public void visitTopLevel(JCCompilationUnit tree) {
229: result = tree.packageAnnotations;
230: }
231:
232: public void visitClassDef(JCClassDecl tree) {
233: result = tree.mods.annotations;
234: }
235:
236: public void visitMethodDef(JCMethodDecl tree) {
237: result = tree.mods.annotations;
238: }
239:
240: public void visitVarDef(JCVariableDecl tree) {
241: result = tree.mods.annotations;
242: }
243: }
244: Vis vis = new Vis();
245: tree.accept(vis);
246: if (vis.result == null)
247: return null;
248: return matchAnnoToTree(cast(Attribute.Compound.class, findme),
249: sym.getAnnotationMirrors(), vis.result);
250: }
251:
252: /**
253: * Returns the tree for an annotation given a list of annotations
254: * in which to search (recursively) and their corresponding trees.
255: * Returns null if the tree cannot be found.
256: */
257: private JCTree matchAnnoToTree(Attribute.Compound findme,
258: List<Attribute.Compound> annos, List<JCAnnotation> trees) {
259: for (Attribute.Compound anno : annos) {
260: for (JCAnnotation tree : trees) {
261: JCTree match = matchAnnoToTree(findme, anno, tree);
262: if (match != null)
263: return match;
264: }
265: }
266: return null;
267: }
268:
269: /**
270: * Returns the tree for an annotation given an Attribute to
271: * search (recursively) and its corresponding tree.
272: * Returns null if the tree cannot be found.
273: */
274: private JCTree matchAnnoToTree(final Attribute.Compound findme,
275: final Attribute attr, final JCTree tree) {
276: if (attr == findme)
277: return (tree.type.tsym == findme.type.tsym) ? tree : null;
278:
279: class Vis implements Attribute.Visitor {
280: JCTree result = null;
281:
282: public void visitConstant(Attribute.Constant value) {
283: }
284:
285: public void visitClass(Attribute.Class clazz) {
286: }
287:
288: public void visitCompound(Attribute.Compound anno) {
289: for (Pair<MethodSymbol, Attribute> pair : anno.values) {
290: JCExpression expr = scanForAssign(pair.fst, tree);
291: if (expr != null) {
292: JCTree match = matchAnnoToTree(findme,
293: pair.snd, expr);
294: if (match != null) {
295: result = match;
296: return;
297: }
298: }
299: }
300: }
301:
302: public void visitArray(Attribute.Array array) {
303: if (tree.getTag() == JCTree.NEWARRAY
304: && types.elemtype(array.type).tsym == findme.type.tsym) {
305: List<JCExpression> elems = ((JCNewArray) tree).elems;
306: for (Attribute value : array.values) {
307: if (value == findme) {
308: result = elems.head;
309: return;
310: }
311: elems = elems.tail;
312: }
313: }
314: }
315:
316: public void visitEnum(Attribute.Enum e) {
317: }
318:
319: public void visitError(Attribute.Error e) {
320: }
321: }
322: Vis vis = new Vis();
323: attr.accept(vis);
324: return vis.result;
325: }
326:
327: /**
328: * Scans for a JCAssign node with a LHS matching a given
329: * symbol, and returns its RHS. Does not scan nested JCAnnotations.
330: */
331: private JCExpression scanForAssign(final MethodSymbol sym,
332: final JCTree tree) {
333: class TS extends TreeScanner {
334: JCExpression result = null;
335:
336: public void scan(JCTree t) {
337: if (t != null && result == null)
338: t.accept(this );
339: }
340:
341: public void visitAnnotation(JCAnnotation t) {
342: if (t == tree)
343: scan(t.args);
344: }
345:
346: public void visitAssign(JCAssign t) {
347: if (t.lhs.getTag() == JCTree.IDENT) {
348: JCIdent ident = (JCIdent) t.lhs;
349: if (ident.sym == sym)
350: result = t.rhs;
351: }
352: }
353: }
354: TS scanner = new TS();
355: tree.accept(scanner);
356: return scanner.result;
357: }
358:
359: /**
360: * Returns the tree node corresponding to this element, or null
361: * if none can be found.
362: */
363: public JCTree getTree(Element e) {
364: Pair<JCTree, ?> treeTop = getTreeAndTopLevel(e);
365: return (treeTop != null) ? treeTop.fst : null;
366: }
367:
368: public String getDocComment(Element e) {
369: // Our doc comment is contained in a map in our toplevel,
370: // indexed by our tree. Find our enter environment, which gives
371: // us our toplevel. It also gives us a tree that contains our
372: // tree: walk it to find our tree. This is painful.
373: Pair<JCTree, JCCompilationUnit> treeTop = getTreeAndTopLevel(e);
374: if (treeTop == null)
375: return null;
376: JCTree tree = treeTop.fst;
377: JCCompilationUnit toplevel = treeTop.snd;
378: if (toplevel.docComments == null)
379: return null;
380: return toplevel.docComments.get(tree);
381: }
382:
383: public PackageElement getPackageOf(Element e) {
384: return cast(Symbol.class, e).packge();
385: }
386:
387: public boolean isDeprecated(Element e) {
388: Symbol sym = cast(Symbol.class, e);
389: return (sym.flags() & Flags.DEPRECATED) != 0;
390: }
391:
392: public Name getBinaryName(TypeElement type) {
393: return cast(TypeSymbol.class, type).flatName();
394: }
395:
396: public Map<MethodSymbol, Attribute> getElementValuesWithDefaults(
397: AnnotationMirror a) {
398: Attribute.Compound anno = cast(Attribute.Compound.class, a);
399: DeclaredType annotype = a.getAnnotationType();
400: Map<MethodSymbol, Attribute> valmap = anno.getElementValues();
401:
402: for (ExecutableElement ex : methodsIn(annotype.asElement()
403: .getEnclosedElements())) {
404: MethodSymbol meth = (MethodSymbol) ex;
405: Attribute defaultValue = meth.getDefaultValue();
406: if (defaultValue != null && !valmap.containsKey(meth)) {
407: valmap.put(meth, defaultValue);
408: }
409: }
410: return valmap;
411: }
412:
413: /**
414: * {@inheritDoc}
415: */
416: public FilteredMemberList getAllMembers(TypeElement element) {
417: Symbol sym = cast(Symbol.class, element);
418: Scope scope = sym.members().dupUnshared();
419: List<Type> closure = types.closure(sym.asType());
420: for (Type t : closure)
421: addMembers(scope, t);
422: return new FilteredMemberList(scope);
423: }
424:
425: // where
426: private void addMembers(Scope scope, Type type) {
427: members: for (Scope.Entry e = type.asElement().members().elems; e != null; e = e.sibling) {
428: Scope.Entry overrider = scope.lookup(e.sym.getSimpleName());
429: while (overrider.scope != null) {
430: if (overrider.sym.kind == e.sym.kind
431: && (overrider.sym.flags() & Flags.SYNTHETIC) == 0) {
432: if (overrider.sym.getKind() == ElementKind.METHOD
433: && overrides(
434: (ExecutableElement) overrider.sym,
435: (ExecutableElement) e.sym,
436: (TypeElement) type.asElement())) {
437: continue members;
438: }
439: }
440: overrider = overrider.next();
441: }
442: boolean derived = e.sym.getEnclosingElement() != scope.owner;
443: ElementKind kind = e.sym.getKind();
444: boolean initializer = kind == ElementKind.CONSTRUCTOR
445: || kind == ElementKind.INSTANCE_INIT
446: || kind == ElementKind.STATIC_INIT;
447: if (!derived
448: || (!initializer && e.sym.isInheritedIn(
449: scope.owner, types)))
450: scope.enter(e.sym);
451: }
452: }
453:
454: /**
455: * Returns all annotations of an element, whether
456: * inherited or directly present.
457: *
458: * @param e the element being examined
459: * @return all annotations of the element
460: */
461: public List<Attribute.Compound> getAllAnnotationMirrors(Element e) {
462: Symbol sym = cast(Symbol.class, e);
463: List<Attribute.Compound> annos = sym.getAnnotationMirrors();
464: while (sym.getKind() == ElementKind.CLASS) {
465: Type sup = ((ClassSymbol) sym).getSuperclass();
466: if (sup.tag != TypeTags.CLASS || sup.isErroneous()
467: || sup.tsym == syms.objectType.tsym) {
468: break;
469: }
470: sym = sup.tsym;
471: List<Attribute.Compound> oldAnnos = annos;
472: for (Attribute.Compound anno : sym.getAnnotationMirrors()) {
473: if (isInherited(anno.type)
474: && !containsAnnoOfType(oldAnnos, anno.type)) {
475: annos = annos.prepend(anno);
476: }
477: }
478: }
479: return annos;
480: }
481:
482: /**
483: * Tests whether an annotation type is @Inherited.
484: */
485: private boolean isInherited(Type annotype) {
486: for (Attribute.Compound anno : annotype.tsym
487: .getAnnotationMirrors()) {
488: if (anno.type.tsym == syms.inheritedType.tsym)
489: return true;
490: }
491: return false;
492: }
493:
494: /**
495: * Tests whether a list of annotations contains an annotation
496: * of a given type.
497: */
498: private static boolean containsAnnoOfType(
499: List<Attribute.Compound> annos, Type type) {
500: for (Attribute.Compound anno : annos) {
501: if (anno.type.tsym == type.tsym)
502: return true;
503: }
504: return false;
505: }
506:
507: public boolean hides(Element hiderEl, Element hideeEl) {
508: Symbol hider = cast(Symbol.class, hiderEl);
509: Symbol hidee = cast(Symbol.class, hideeEl);
510:
511: // Fields only hide fields; methods only methods; types only types.
512: // Names must match. Nothing hides itself (just try it).
513: if (hider == hidee || hider.kind != hidee.kind
514: || hider.name != hidee.name) {
515: return false;
516: }
517:
518: // Only static methods can hide other methods.
519: // Methods only hide methods with matching signatures.
520: if (hider.kind == Kinds.MTH) {
521: if (!hider.isStatic()
522: || !types.isSubSignature(hider.type, hidee.type)) {
523: return false;
524: }
525: }
526:
527: // Hider must be in a subclass of hidee's class.
528: // Note that if M1 hides M2, and M2 hides M3, and M3 is accessible
529: // in M1's class, then M1 and M2 both hide M3.
530: ClassSymbol hiderClass = hider.owner.enclClass();
531: ClassSymbol hideeClass = hidee.owner.enclClass();
532: if (hiderClass == null || hideeClass == null
533: || !hiderClass.isSubClass(hideeClass, types)) {
534: return false;
535: }
536:
537: // Hidee must be accessible in hider's class.
538: // The method isInheritedIn is poorly named: it checks only access.
539: return hidee.isInheritedIn(hiderClass, types);
540: }
541:
542: public boolean overrides(ExecutableElement riderEl,
543: ExecutableElement rideeEl, TypeElement typeEl) {
544: MethodSymbol rider = cast(MethodSymbol.class, riderEl);
545: MethodSymbol ridee = cast(MethodSymbol.class, rideeEl);
546: ClassSymbol origin = cast(ClassSymbol.class, typeEl);
547:
548: return rider.name == ridee.name &&
549:
550: // not reflexive as per JLS
551: rider != ridee &&
552:
553: // we don't care if ridee is static, though that wouldn't
554: // compile
555: !rider.isStatic() &&
556:
557: // Symbol.overrides assumes the following
558: ridee.isMemberOf(origin, types) &&
559:
560: // check access and signatures; don't check return types
561: rider.overrides(ridee, origin, types, false);
562: }
563:
564: public String getConstantExpression(Object value) {
565: return Constants.format(value);
566: }
567:
568: /**
569: * Print a representation of the elements to the given writer in
570: * the specified order. The main purpose of this method is for
571: * diagnostics. The exact format of the output is <em>not</em>
572: * specified and is subject to change.
573: *
574: * @param w the writer to print the output to
575: * @param elements the elements to print
576: */
577: public void printElements(java.io.Writer w, Element... elements) {
578: for (Element element : elements)
579: (new PrintingProcessor.PrintingElementVisitor(w, this ))
580: .visit(element).flush();
581: }
582:
583: public Name getName(CharSequence cs) {
584: return Name.fromString(names, cs.toString());
585: }
586:
587: /**
588: * Returns the tree node and compilation unit corresponding to this
589: * element, or null if they can't be found.
590: */
591: private Pair<JCTree, JCCompilationUnit> getTreeAndTopLevel(Element e) {
592: Symbol sym = cast(Symbol.class, e);
593: Env<AttrContext> enterEnv = getEnterEnv(sym);
594: if (enterEnv == null)
595: return null;
596: JCTree tree = TreeInfo.declarationFor(sym, enterEnv.tree);
597: if (tree == null || enterEnv.toplevel == null)
598: return null;
599: return new Pair<JCTree, JCCompilationUnit>(tree,
600: enterEnv.toplevel);
601: }
602:
603: /**
604: * Returns the best approximation for the tree node and compilation unit
605: * corresponding to the given element, annotation and value.
606: * If the element is null, null is returned.
607: * If the annotation is null or cannot be found, the tree node and
608: * compilation unit for the element is returned.
609: * If the annotation value is null or cannot be found, the tree node and
610: * compilation unit for the annotation is returned.
611: */
612: public Pair<JCTree, JCCompilationUnit> getTreeAndTopLevel(
613: Element e, AnnotationMirror a, AnnotationValue v) {
614: if (e == null)
615: return null;
616:
617: Pair<JCTree, JCCompilationUnit> elemTreeTop = getTreeAndTopLevel(e);
618: if (elemTreeTop == null)
619: return null;
620:
621: if (a == null)
622: return elemTreeTop;
623:
624: JCTree annoTree = matchAnnoToTree(a, e, elemTreeTop.fst);
625: if (annoTree == null)
626: return elemTreeTop;
627:
628: // 6388543: if v != null, we should search within annoTree to find
629: // the tree matching v. For now, we ignore v and return the tree of
630: // the annotation.
631: return new Pair<JCTree, JCCompilationUnit>(annoTree,
632: elemTreeTop.snd);
633: }
634:
635: /**
636: * Returns a symbol's enter environment, or null if it has none.
637: */
638: private Env<AttrContext> getEnterEnv(Symbol sym) {
639: // Get enclosing class of sym, or sym itself if it is a class
640: // or package.
641: TypeSymbol ts = (sym.kind != Kinds.PCK) ? sym.enclClass()
642: : (PackageSymbol) sym;
643: return (ts != null) ? enter.getEnv(ts) : null;
644: }
645:
646: /**
647: * Returns an object cast to the specified type.
648: * @throws NullPointerException if the object is {@code null}
649: * @throws IllegalArgumentException if the object is of the wrong type
650: */
651: private static <T> T cast(Class<T> clazz, Object o) {
652: if (!clazz.isInstance(o))
653: throw new IllegalArgumentException(o.toString());
654: return clazz.cast(o);
655: }
656: }
|