1 /* 2 * Copyright 2004-2006 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.util.HashMap; 30 import java.util.Map; 31 32 import com.sun.mirror.declaration.*; 33 import com.sun.tools.apt.mirror.AptEnv; 34 import com.sun.tools.javac.code.*; 35 import com.sun.tools.javac.code.Symbol.*; 36 import com.sun.tools.javac.util.Context; 37 import com.sun.tools.javac.util.Name; 38 import com.sun.tools.javac.main.JavaCompiler; 39 40 /** 41 * Utilities for constructing and caching declarations. 42 */ 43 @SuppressWarnings("deprecation") 44 public class DeclarationMaker { 45 46 private AptEnv env; 47 private Context context; 48 private JavaCompiler javacompiler; 49 private static final Context.Key<DeclarationMaker> declarationMakerKey = 50 new Context.Key<DeclarationMaker>(); 51 52 public static DeclarationMaker instance(Context context) { 53 DeclarationMaker instance = context.get(declarationMakerKey); 54 if (instance == null) { 55 instance = new DeclarationMaker(context); 56 } 57 return instance; 58 } 59 60 private DeclarationMaker(Context context) { 61 context.put(declarationMakerKey, this); 62 env = AptEnv.instance(context); 63 this.context = context; 64 this.javacompiler = JavaCompiler.instance(context); 65 } 66 67 68 69 // Cache of package declarations 70 private Map<PackageSymbol, PackageDeclaration> packageDecls = 71 new HashMap<PackageSymbol, PackageDeclaration>(); 72 73 /** 74 * Returns the package declaration for a package symbol. 75 */ 76 public PackageDeclaration getPackageDeclaration(PackageSymbol p) { 77 PackageDeclaration res = packageDecls.get(p); 78 if (res == null) { 79 res = new PackageDeclarationImpl(env, p); 80 packageDecls.put(p, res); 81 } 82 return res; 83 } 84 85 /** 86 * Returns the package declaration for the package with the given name. 87 * Name is fully-qualified, or "" for the unnamed package. 88 * Returns null if package declaration not found. 89 */ 90 public PackageDeclaration getPackageDeclaration(String name) { 91 PackageSymbol p = null; 92 if (name.equals("") ) 93 p = env.symtab.unnamedPackage; 94 else { 95 if (!isJavaName(name)) 96 return null; 97 Symbol s = nameToSymbol(name, false); 98 if (s instanceof PackageSymbol) { 99 p = (PackageSymbol) s; 100 if (!p.exists()) 101 return null; 102 } else 103 return null; 104 } 105 return getPackageDeclaration(p); 106 } 107 108 // Cache of type declarations 109 private Map<ClassSymbol, TypeDeclaration> typeDecls = 110 new HashMap<ClassSymbol, TypeDeclaration>(); 111 112 /** 113 * Returns the type declaration for a class symbol. 114 * Forces completion, and returns null on error. 115 */ 116 public TypeDeclaration getTypeDeclaration(ClassSymbol c) { 117 long flags = AptEnv.getFlags(c); // forces symbol completion 118 if (c.kind == Kinds.ERR) { 119 return null; 120 } 121 TypeDeclaration res = typeDecls.get(c); 122 if (res == null) { 123 if ((flags & Flags.ANNOTATION) != 0) { 124 res = new AnnotationTypeDeclarationImpl(env, c); 125 } else if ((flags & Flags.INTERFACE) != 0) { 126 res = new InterfaceDeclarationImpl(env, c); 127 } else if ((flags & Flags.ENUM) != 0) { 128 res = new EnumDeclarationImpl(env, c); 129 } else { 130 res = new ClassDeclarationImpl(env, c); 131 } 132 typeDecls.put(c, res); 133 } 134 return res; 135 } 136 137 /** 138 * Returns the type declaration for the type with the given canonical name. 139 * Returns null if type declaration not found. 140 */ 141 public TypeDeclaration getTypeDeclaration(String name) { 142 if (!isJavaName(name)) 143 return null; 144 Symbol s = nameToSymbol(name, true); 145 if (s instanceof ClassSymbol) { 146 ClassSymbol c = (ClassSymbol) s; 147 return getTypeDeclaration(c); 148 } else 149 return null; 150 } 151 152 /** 153 * Returns a symbol given the type's or packages's canonical name, 154 * or null if the name isn't found. 155 */ 156 private Symbol nameToSymbol(String name, boolean classCache) { 157 Symbol s = null; 158 Name nameName = env.names.fromString(name); 159 if (classCache) 160 s = env.symtab.classes.get(nameName); 161 else 162 s = env.symtab.packages.get(nameName); 163 164 if (s != null && s.exists()) 165 return s; 166 167 s = javacompiler.resolveIdent(name); 168 if (s.kind == Kinds.ERR ) 169 return null; 170 171 if (s.kind == Kinds.PCK) 172 s.complete(); 173 174 return s; 175 } 176 177 // Cache of method and constructor declarations 178 private Map<MethodSymbol, ExecutableDeclaration> executableDecls = 179 new HashMap<MethodSymbol, ExecutableDeclaration>(); 180 181 /** 182 * Returns the method or constructor declaration for a method symbol. 183 */ 184 ExecutableDeclaration getExecutableDeclaration(MethodSymbol m) { 185 ExecutableDeclaration res = executableDecls.get(m); 186 if (res == null) { 187 if (m.isConstructor()) { 188 res = new ConstructorDeclarationImpl(env, m); 189 } else if (isAnnotationTypeElement(m)) { 190 res = new AnnotationTypeElementDeclarationImpl(env, m); 191 } else { 192 res = new MethodDeclarationImpl(env, m); 193 } 194 executableDecls.put(m, res); 195 } 196 return res; 197 } 198 199 // Cache of field declarations 200 private Map<VarSymbol, FieldDeclaration> fieldDecls = 201 new HashMap<VarSymbol, FieldDeclaration>(); 202 203 /** 204 * Returns the field declaration for a var symbol. 205 */ 206 FieldDeclaration getFieldDeclaration(VarSymbol v) { 207 FieldDeclaration res = fieldDecls.get(v); 208 if (res == null) { 209 if (hasFlag(v, Flags.ENUM)) { 210 res = new EnumConstantDeclarationImpl(env, v); 211 } else { 212 res = new FieldDeclarationImpl(env, v); 213 } 214 fieldDecls.put(v, res); 215 } 216 return res; 217 } 218 219 /** 220 * Returns a parameter declaration. 221 */ 222 ParameterDeclaration getParameterDeclaration(VarSymbol v) { 223 return new ParameterDeclarationImpl(env, v); 224 } 225 226 /** 227 * Returns a type parameter declaration. 228 */ 229 public TypeParameterDeclaration getTypeParameterDeclaration(TypeSymbol t) { 230 return new TypeParameterDeclarationImpl(env, t); 231 } 232 233 /** 234 * Returns an annotation. 235 */ 236 AnnotationMirror getAnnotationMirror(Attribute.Compound a, Declaration decl) { 237 return new AnnotationMirrorImpl(env, a, decl); 238 } 239 240 241 /** 242 * Is a string a valid Java identifier? 243 */ 244 public static boolean isJavaIdentifier(String id) { 245 return javax.lang.model.SourceVersion.isIdentifier(id); 246 } 247 248 public static boolean isJavaName(String name) { 249 for(String id: name.split("\\.")) { 250 if (! isJavaIdentifier(id)) 251 return false; 252 } 253 return true; 254 } 255 256 /** 257 * Is a method an annotation type element? 258 * It is if it's declared in an annotation type. 259 */ 260 private static boolean isAnnotationTypeElement(MethodSymbol m) { 261 return hasFlag(m.enclClass(), Flags.ANNOTATION); 262 } 263 264 /** 265 * Does a symbol have a given flag? 266 */ 267 private static boolean hasFlag(Symbol s, long flag) { 268 return AptEnv.hasFlag(s, flag); 269 } 270 }