1 /* 2 * Copyright 2004-2005 Sun Microsystems, Inc. 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. Sun designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, 22 * CA 95054 USA or visit www.sun.com if you need additional information or 23 * have any questions. 24 */ 25 26 package com.sun.tools.apt.mirror.declaration; 27 28 29 import java.lang.annotation.Annotation; 30 import java.util.ArrayList; 31 import java.util.LinkedList; 32 import java.util.Collection; 33 import java.util.EnumSet; 34 import javax.tools.JavaFileObject; 35 36 import com.sun.mirror.declaration.*; 37 import com.sun.mirror.util.*; 38 import com.sun.tools.apt.mirror.AptEnv; 39 import com.sun.tools.apt.mirror.util.SourcePositionImpl; 40 import com.sun.tools.javac.code.*; 41 import com.sun.tools.javac.code.Symbol.*; 42 import com.sun.tools.javac.comp.AttrContext; 43 import com.sun.tools.javac.comp.Env; 44 import com.sun.tools.javac.tree.*; 45 import com.sun.tools.javac.util.Name; 46 import com.sun.tools.javac.util.Position; 47 48 import static com.sun.mirror.declaration.Modifier.*; 49 import static com.sun.tools.javac.code.Kinds.*; 50 51 52 /** 53 * Implementation of Declaration 54 */ 55 56 public abstract class DeclarationImpl implements Declaration { 57 58 protected final AptEnv env; 59 public final Symbol sym; 60 61 protected static DeclarationFilter identityFilter = 62 new DeclarationFilter(); 63 64 65 /** 66 * "sym" should be completed before this constructor is called. 67 */ 68 protected DeclarationImpl(AptEnv env, Symbol sym) { 69 this.env = env; 70 this.sym = sym; 71 } 72 73 74 /** 75 * {@inheritDoc} 76 * <p> ParameterDeclarationImpl overrides this implementation. 77 */ 78 public boolean equals(Object obj) { 79 if (obj instanceof DeclarationImpl) { 80 DeclarationImpl that = (DeclarationImpl) obj; 81 return sym == that.sym && env == that.env; 82 } else { 83 return false; 84 } 85 } 86 87 /** 88 * {@inheritDoc} 89 * <p> ParameterDeclarationImpl overrides this implementation. 90 */ 91 public int hashCode() { 92 return sym.hashCode() + env.hashCode(); 93 } 94 95 /** 96 * {@inheritDoc} 97 */ 98 public String getDocComment() { 99 // Our doc comment is contained in a map in our toplevel, 100 // indexed by our tree. Find our enter environment, which gives 101 // us our toplevel. It also gives us a tree that contains our 102 // tree: walk it to find our tree. This is painful. 103 Env<AttrContext> enterEnv = getEnterEnv(); 104 if (enterEnv == null) 105 return null; 106 JCTree tree = TreeInfo.declarationFor(sym, enterEnv.tree); 107 return enterEnv.toplevel.docComments.get(tree); 108 } 109 110 /** 111 * {@inheritDoc} 112 */ 113 public Collection<AnnotationMirror> getAnnotationMirrors() { 114 Collection<AnnotationMirror> res = 115 new ArrayList<AnnotationMirror>(); 116 for (Attribute.Compound a : sym.getAnnotationMirrors()) { 117 res.add(env.declMaker.getAnnotationMirror(a, this)); 118 } 119 return res; 120 } 121 122 /** 123 * {@inheritDoc} 124 * Overridden by ClassDeclarationImpl to handle @Inherited. 125 */ 126 public <A extends Annotation> A getAnnotation(Class<A> annoType) { 127 return getAnnotation(annoType, sym); 128 } 129 130 protected <A extends Annotation> A getAnnotation(Class<A> annoType, 131 Symbol annotated) { 132 if (!annoType.isAnnotation()) { 133 throw new IllegalArgumentException( 134 "Not an annotation type: " + annoType); 135 } 136 String name = annoType.getName(); 137 for (Attribute.Compound attr : annotated.getAnnotationMirrors()) { 138 if (name.equals(attr.type.tsym.flatName().toString())) { 139 return AnnotationProxyMaker.generateAnnotation(env, attr, 140 annoType); 141 } 142 } 143 return null; 144 } 145 146 // Cache for modifiers. 147 private EnumSet<Modifier> modifiers = null; 148 149 /** 150 * {@inheritDoc} 151 */ 152 public Collection<Modifier> getModifiers() { 153 if (modifiers == null) { 154 modifiers = EnumSet.noneOf(Modifier.class); 155 long flags = AptEnv.getFlags(sym); 156 157 if (0 != (flags & Flags.PUBLIC)) modifiers.add(PUBLIC); 158 if (0 != (flags & Flags.PROTECTED)) modifiers.add(PROTECTED); 159 if (0 != (flags & Flags.PRIVATE)) modifiers.add(PRIVATE); 160 if (0 != (flags & Flags.ABSTRACT)) modifiers.add(ABSTRACT); 161 if (0 != (flags & Flags.STATIC)) modifiers.add(STATIC); 162 if (0 != (flags & Flags.FINAL)) modifiers.add(FINAL); 163 if (0 != (flags & Flags.TRANSIENT)) modifiers.add(TRANSIENT); 164 if (0 != (flags & Flags.VOLATILE)) modifiers.add(VOLATILE); 165 if (0 != (flags & Flags.SYNCHRONIZED)) modifiers.add(SYNCHRONIZED); 166 if (0 != (flags & Flags.NATIVE)) modifiers.add(NATIVE); 167 if (0 != (flags & Flags.STRICTFP)) modifiers.add(STRICTFP); 168 } 169 return modifiers; 170 } 171 172 /** 173 * {@inheritDoc} 174 * Overridden in some subclasses. 175 */ 176 public String getSimpleName() { 177 return sym.name.toString(); 178 } 179 180 /** 181 * {@inheritDoc} 182 */ 183 public SourcePosition getPosition() { 184 // Find the toplevel. From there use a tree-walking utility 185 // that finds the tree for our symbol, and with it the position. 186 Env<AttrContext> enterEnv = getEnterEnv(); 187 if (enterEnv == null) 188 return null; 189 JCTree.JCCompilationUnit toplevel = enterEnv.toplevel; 190 JavaFileObject sourcefile = toplevel.sourcefile; 191 if (sourcefile == null) 192 return null; 193 int pos = TreeInfo.positionFor(sym, toplevel); 194 195 return new SourcePositionImpl(sourcefile, pos, toplevel.lineMap); 196 } 197 198 /** 199 * Applies a visitor to this declaration. 200 * 201 * @param v the visitor operating on this declaration 202 */ 203 public void accept(DeclarationVisitor v) { 204 v.visitDeclaration(this); 205 } 206 207 208 private Collection<Symbol> members = null; // cache for getMembers() 209 210 /** 211 * Returns the symbols of type or package members (and constructors) 212 * that are not synthetic or otherwise unwanted. 213 * Caches the result if "cache" is true. 214 */ 215 protected Collection<Symbol> getMembers(boolean cache) { 216 if (members != null) { 217 return members; 218 } 219 LinkedList<Symbol> res = new LinkedList<Symbol>(); 220 for (Scope.Entry e = sym.members().elems; e != null; e = e.sibling) { 221 if (e.sym != null && !unwanted(e.sym)) { 222 res.addFirst(e.sym); 223 } 224 } 225 return cache ? (members = res) : res; 226 } 227 228 /** 229 * Tests whether this is a symbol that should never be seen by clients, 230 * such as a synthetic class. 231 * Note that a class synthesized by the compiler may not be flagged as 232 * synthetic: see bugid 4959932. 233 */ 234 private static boolean unwanted(Symbol s) { 235 return AptEnv.hasFlag(s, Flags.SYNTHETIC) || 236 (s.kind == TYP && 237 !DeclarationMaker.isJavaIdentifier(s.name.toString())); 238 } 239 240 /** 241 * Returns this declaration's enter environment, or null if it 242 * has none. 243 */ 244 private Env<AttrContext> getEnterEnv() { 245 // Get enclosing class of sym, or sym itself if it is a class 246 // or package. 247 TypeSymbol ts = (sym.kind != PCK) 248 ? sym.enclClass() 249 : (PackageSymbol) sym; 250 return (ts != null) 251 ? env.enter.getEnv(ts) 252 : null; 253 } 254 }