001 /*
002 * Copyright 2004-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.apt.mirror.declaration;
027
028
029 import java.util.HashMap;
030 import java.util.Map;
031
032 import com.sun.mirror.declaration.*;
033 import com.sun.tools.apt.mirror.AptEnv;
034 import com.sun.tools.javac.code.*;
035 import com.sun.tools.javac.code.Symbol.*;
036 import com.sun.tools.javac.util.Context;
037 import com.sun.tools.javac.util.Name;
038 import com.sun.tools.javac.main.JavaCompiler;
039
040 /**
041 * Utilities for constructing and caching declarations.
042 */
043
044 public class DeclarationMaker {
045
046 private AptEnv env;
047 private Context context;
048 private JavaCompiler javacompiler;
049 private static final Context.Key<DeclarationMaker> declarationMakerKey =
050 new Context.Key<DeclarationMaker>();
051
052 public static DeclarationMaker instance(Context context) {
053 DeclarationMaker instance = context.get(declarationMakerKey);
054 if (instance == null) {
055 instance = new DeclarationMaker(context);
056 }
057 return instance;
058 }
059
060 private DeclarationMaker(Context context) {
061 context.put(declarationMakerKey, this);
062 env = AptEnv.instance(context);
063 this.context = context;
064 this.javacompiler = JavaCompiler.instance(context);
065 }
066
067
068
069 // Cache of package declarations
070 private Map<PackageSymbol, PackageDeclaration> packageDecls =
071 new HashMap<PackageSymbol, PackageDeclaration>();
072
073 /**
074 * Returns the package declaration for a package symbol.
075 */
076 public PackageDeclaration getPackageDeclaration(PackageSymbol p) {
077 PackageDeclaration res = packageDecls.get(p);
078 if (res == null) {
079 res = new PackageDeclarationImpl(env, p);
080 packageDecls.put(p, res);
081 }
082 return res;
083 }
084
085 /**
086 * Returns the package declaration for the package with the given name.
087 * Name is fully-qualified, or "" for the unnamed package.
088 * Returns null if package declaration not found.
089 */
090 public PackageDeclaration getPackageDeclaration(String name) {
091 PackageSymbol p = null;
092 if (name.equals("") )
093 p = env.symtab.unnamedPackage;
094 else {
095 if (!isJavaName(name))
096 return null;
097 Symbol s = nameToSymbol(name, false);
098 if (s instanceof PackageSymbol) {
099 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 }