001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common Development
008: * and Distribution License("CDDL") (collectively, the "License"). You
009: * may not use this file except in compliance with the License. You can obtain
010: * a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html
011: * or glassfish/bootstrap/legal/LICENSE.txt. See the License for the specific
012: * language governing permissions and limitations under the License.
013: *
014: * When distributing the software, include this License Header Notice in each
015: * file and include the License file at glassfish/bootstrap/legal/LICENSE.txt.
016: * Sun designates this particular file as subject to the "Classpath" exception
017: * as provided by Sun in the GPL Version 2 section of the License file that
018: * accompanied this code. If applicable, add the following below the License
019: * Header, with the fields enclosed by brackets [] replaced by your own
020: * identifying information: "Portions Copyrighted [year]
021: * [name of copyright owner]"
022: *
023: * Contributor(s):
024: *
025: * If you wish your version of this file to be governed by only the CDDL or
026: * only the GPL Version 2, indicate your decision by adding "[Contributor]
027: * elects to include this software in this distribution under the [CDDL or GPL
028: * Version 2] license." If you don't indicate a single choice of license, a
029: * recipient has the option to distribute your version of this file under
030: * either the CDDL, the GPL Version 2 or to extend the choice of license to
031: * its licensees as provided above. However, if you add GPL Version 2 code
032: * and therefore, elected the GPL Version 2 license, then the option applies
033: * only if the new code is made subject to such option by the copyright
034: * holder.
035: */
036:
037: package com.sun.tools.jxc.model.nav;
038:
039: import java.util.ArrayList;
040: import java.util.Collection;
041: import java.util.Collections;
042: import java.util.Comparator;
043: import java.util.HashMap;
044: import java.util.List;
045: import java.util.Map;
046:
047: import com.sun.istack.tools.APTTypeVisitor;
048: import com.sun.mirror.apt.AnnotationProcessorEnvironment;
049: import com.sun.mirror.declaration.ClassDeclaration;
050: import com.sun.mirror.declaration.ConstructorDeclaration;
051: import com.sun.mirror.declaration.Declaration;
052: import com.sun.mirror.declaration.EnumConstantDeclaration;
053: import com.sun.mirror.declaration.EnumDeclaration;
054: import com.sun.mirror.declaration.FieldDeclaration;
055: import com.sun.mirror.declaration.InterfaceDeclaration;
056: import com.sun.mirror.declaration.MemberDeclaration;
057: import com.sun.mirror.declaration.MethodDeclaration;
058: import com.sun.mirror.declaration.Modifier;
059: import com.sun.mirror.declaration.ParameterDeclaration;
060: import com.sun.mirror.declaration.TypeDeclaration;
061: import com.sun.mirror.type.ArrayType;
062: import com.sun.mirror.type.ClassType;
063: import com.sun.mirror.type.DeclaredType;
064: import com.sun.mirror.type.InterfaceType;
065: import com.sun.mirror.type.PrimitiveType;
066: import com.sun.mirror.type.ReferenceType;
067: import com.sun.mirror.type.TypeMirror;
068: import com.sun.mirror.type.TypeVariable;
069: import com.sun.mirror.type.VoidType;
070: import com.sun.mirror.type.WildcardType;
071: import com.sun.mirror.util.Declarations;
072: import com.sun.mirror.util.SourcePosition;
073: import com.sun.mirror.util.TypeVisitor;
074: import com.sun.mirror.util.Types;
075: import com.sun.xml.bind.v2.model.nav.Navigator;
076: import com.sun.xml.bind.v2.runtime.Location;
077:
078: /**
079: * {@link Navigator} implementation for APT.
080: *
081: * TODO: check the spec on how generics are supposed to be handled
082: *
083: * @author Kohsuke Kawaguchi (kk@kohsuke.org)
084: */
085: public class APTNavigator
086: implements
087: Navigator<TypeMirror, TypeDeclaration, FieldDeclaration, MethodDeclaration> {
088:
089: private final AnnotationProcessorEnvironment env;
090:
091: private final PrimitiveType primitiveByte;
092:
093: public APTNavigator(AnnotationProcessorEnvironment env) {
094: this .env = env;
095: this .primitiveByte = env.getTypeUtils().getPrimitiveType(
096: PrimitiveType.Kind.BYTE);
097: }
098:
099: public TypeDeclaration getSuperClass(TypeDeclaration t) {
100: if (t instanceof ClassDeclaration) {
101: ClassDeclaration c = (ClassDeclaration) t;
102: ClassType sup = c.getSuperclass();
103: if (sup != null)
104: return sup.getDeclaration();
105: else
106: return null;
107: }
108: return env.getTypeDeclaration(Object.class.getName());
109: }
110:
111: public TypeMirror getBaseClass(TypeMirror type, TypeDeclaration sup) {
112: return baseClassFinder.apply(type, sup);
113: }
114:
115: public String getClassName(TypeDeclaration t) {
116: return t.getQualifiedName();
117: }
118:
119: public String getTypeName(TypeMirror typeMirror) {
120: return typeMirror.toString();
121: }
122:
123: public String getClassShortName(TypeDeclaration t) {
124: return t.getSimpleName();
125: }
126:
127: public Collection<FieldDeclaration> getDeclaredFields(
128: TypeDeclaration c) {
129: List<FieldDeclaration> l = new ArrayList<FieldDeclaration>(c
130: .getFields());
131: return sort(l);
132: }
133:
134: public FieldDeclaration getDeclaredField(TypeDeclaration clazz,
135: String fieldName) {
136: for (FieldDeclaration fd : clazz.getFields()) {
137: if (fd.getSimpleName().equals(fieldName))
138: return fd;
139: }
140: return null;
141: }
142:
143: public Collection<MethodDeclaration> getDeclaredMethods(
144: TypeDeclaration c) {
145: List<MethodDeclaration> l = new ArrayList<MethodDeclaration>(c
146: .getMethods());
147: return sort(l);
148: }
149:
150: private <A extends Declaration> List<A> sort(List<A> l) {
151: if (l.isEmpty())
152: return l;
153:
154: // APT supports the operation mode where it creates Declarations from
155: // a class file, in which case the source position is not available
156: // use that as a key to sort them correctly. This isn't "correct" in
157: // the sense that it relies on undocumented behavior of APT where
158: // it returns declarations in the reverse order, but this makes things work.
159: SourcePosition pos = l.get(0).getPosition();
160: if (pos != null)
161: Collections.sort(l, SOURCE_POS_COMPARATOR);
162: else
163: Collections.reverse(l);
164: return l;
165: }
166:
167: public ClassDeclaration getDeclaringClassForField(FieldDeclaration f) {
168: return (ClassDeclaration) f.getDeclaringType();
169: }
170:
171: public ClassDeclaration getDeclaringClassForMethod(
172: MethodDeclaration m) {
173: return (ClassDeclaration) m.getDeclaringType();
174: }
175:
176: public TypeMirror getFieldType(FieldDeclaration f) {
177: return f.getType();
178: }
179:
180: public String getFieldName(FieldDeclaration f) {
181: return f.getSimpleName();
182: }
183:
184: public String getMethodName(MethodDeclaration m) {
185: return m.getSimpleName();
186: }
187:
188: public TypeMirror getReturnType(MethodDeclaration m) {
189: return m.getReturnType();
190: }
191:
192: public TypeMirror[] getMethodParameters(MethodDeclaration m) {
193: Collection<ParameterDeclaration> ps = m.getParameters();
194: TypeMirror[] r = new TypeMirror[ps.size()];
195: int i = 0;
196: for (ParameterDeclaration p : ps)
197: r[i++] = p.getType();
198: return r;
199: }
200:
201: public boolean isStaticMethod(MethodDeclaration m) {
202: return hasModifier(m, Modifier.STATIC);
203: }
204:
205: private boolean hasModifier(Declaration d, Modifier mod) {
206: return d.getModifiers().contains(mod);
207: }
208:
209: public boolean isSubClassOf(TypeMirror sub, TypeMirror sup) {
210: if (sup == DUMMY)
211: // see ref(). if the sub type is known to APT,
212: // its base class must be known. Thus if the sup is DUMMY,
213: // it cannot possibly be the super type.
214: return false;
215: return env.getTypeUtils().isSubtype(sub, sup);
216: }
217:
218: private String getSourceClassName(Class clazz) {
219: Class<?> d = clazz.getDeclaringClass();
220: if (d == null)
221: return clazz.getName();
222: else {
223: String shortName = clazz.getName().substring(
224: d.getName().length() + 1/*for $*/);
225: return getSourceClassName(d) + '.' + shortName;
226: }
227: }
228:
229: public TypeMirror ref(Class c) {
230: if (c.isArray())
231: return env.getTypeUtils().getArrayType(
232: ref(c.getComponentType()));
233: if (c.isPrimitive())
234: return getPrimitive(c);
235: TypeDeclaration t = env
236: .getTypeDeclaration(getSourceClassName(c));
237: // APT only operates on a set of classes used in the compilation,
238: // and it won't recognize additional classes (even if they are visible from javac)
239: // and return null.
240: //
241: // this is causing a problem where we check if a type is collection.
242: // so until the problem is fixed in APT, work around the issue
243: // by returning a dummy token
244: if (t == null)
245: return DUMMY;
246: return env.getTypeUtils().getDeclaredType(t);
247: }
248:
249: public TypeMirror use(TypeDeclaration t) {
250: assert t != null;
251: return env.getTypeUtils().getDeclaredType(t);
252: }
253:
254: public TypeDeclaration asDecl(TypeMirror m) {
255: m = env.getTypeUtils().getErasure(m);
256: if (m instanceof DeclaredType) {
257: DeclaredType d = (DeclaredType) m;
258: return d.getDeclaration();
259: } else
260: return null;
261: }
262:
263: public TypeDeclaration asDecl(Class c) {
264: return env.getTypeDeclaration(getSourceClassName(c));
265: }
266:
267: public <T> TypeMirror erasure(TypeMirror t) {
268: Types tu = env.getTypeUtils();
269: t = tu.getErasure(t);
270: if (t instanceof DeclaredType) {
271: DeclaredType dt = (DeclaredType) t;
272: if (!dt.getActualTypeArguments().isEmpty())
273: return tu.getDeclaredType(dt.getDeclaration());
274: }
275: return t;
276: }
277:
278: public boolean isAbstract(TypeDeclaration clazz) {
279: return hasModifier(clazz, Modifier.ABSTRACT);
280: }
281:
282: public boolean isFinal(TypeDeclaration clazz) {
283: return hasModifier(clazz, Modifier.FINAL);
284: }
285:
286: public FieldDeclaration[] getEnumConstants(TypeDeclaration clazz) {
287: EnumDeclaration ed = (EnumDeclaration) clazz;
288: Collection<EnumConstantDeclaration> constants = ed
289: .getEnumConstants();
290: return constants.toArray(new EnumConstantDeclaration[constants
291: .size()]);
292: }
293:
294: public TypeMirror getVoidType() {
295: return env.getTypeUtils().getVoidType();
296: }
297:
298: public String getPackageName(TypeDeclaration clazz) {
299: return clazz.getPackage().getQualifiedName();
300: }
301:
302: public TypeDeclaration findClass(String className,
303: TypeDeclaration referencePoint) {
304: return env.getTypeDeclaration(className);
305: }
306:
307: public boolean isBridgeMethod(MethodDeclaration method) {
308: return method.getModifiers().contains(Modifier.VOLATILE);
309: }
310:
311: public boolean isOverriding(MethodDeclaration method,
312: TypeDeclaration base) {
313: ClassDeclaration sc = (ClassDeclaration) base;
314:
315: Declarations declUtil = env.getDeclarationUtils();
316:
317: while (true) {
318: for (MethodDeclaration m : sc.getMethods()) {
319: if (declUtil.overrides(method, m))
320: return true;
321: }
322:
323: if (sc.getSuperclass() == null)
324: return false;
325: sc = sc.getSuperclass().getDeclaration();
326: }
327: }
328:
329: public boolean isInterface(TypeDeclaration clazz) {
330: return clazz instanceof InterfaceDeclaration;
331: }
332:
333: public boolean isTransient(FieldDeclaration f) {
334: return f.getModifiers().contains(Modifier.TRANSIENT);
335: }
336:
337: public boolean isInnerClass(TypeDeclaration clazz) {
338: return clazz.getDeclaringType() != null
339: && !clazz.getModifiers().contains(Modifier.STATIC);
340: }
341:
342: public boolean isArray(TypeMirror t) {
343: return t instanceof ArrayType;
344: }
345:
346: public boolean isArrayButNotByteArray(TypeMirror t) {
347: if (!isArray(t))
348: return false;
349:
350: ArrayType at = (ArrayType) t;
351: TypeMirror ct = at.getComponentType();
352:
353: return !ct.equals(primitiveByte);
354: }
355:
356: public TypeMirror getComponentType(TypeMirror t) {
357: if (t instanceof ArrayType) {
358: ArrayType at = (ArrayType) t;
359: return at.getComponentType();
360: }
361:
362: throw new IllegalArgumentException();
363: }
364:
365: public TypeMirror getTypeArgument(TypeMirror typeMirror, int i) {
366: if (typeMirror instanceof DeclaredType) {
367: DeclaredType d = (DeclaredType) typeMirror;
368: TypeMirror[] args = d.getActualTypeArguments().toArray(
369: new TypeMirror[0]);
370: return args[i];
371: } else
372: throw new IllegalArgumentException();
373: }
374:
375: public boolean isParameterizedType(TypeMirror t) {
376: if (t instanceof DeclaredType) {
377: DeclaredType d = (DeclaredType) t;
378: return !d.getActualTypeArguments().isEmpty();
379: }
380: return false;
381: }
382:
383: public boolean isPrimitive(TypeMirror t) {
384: return t instanceof PrimitiveType;
385: }
386:
387: private static final Map<Class, PrimitiveType.Kind> primitives = new HashMap<Class, PrimitiveType.Kind>();
388:
389: static {
390: primitives.put(Integer.TYPE, PrimitiveType.Kind.INT);
391: primitives.put(Byte.TYPE, PrimitiveType.Kind.BYTE);
392: primitives.put(Float.TYPE, PrimitiveType.Kind.FLOAT);
393: primitives.put(Boolean.TYPE, PrimitiveType.Kind.BOOLEAN);
394: primitives.put(Short.TYPE, PrimitiveType.Kind.SHORT);
395: primitives.put(Long.TYPE, PrimitiveType.Kind.LONG);
396: primitives.put(Double.TYPE, PrimitiveType.Kind.DOUBLE);
397: primitives.put(Character.TYPE, PrimitiveType.Kind.CHAR);
398:
399: }
400:
401: public TypeMirror getPrimitive(Class primitiveType) {
402: assert primitiveType.isPrimitive();
403: if (primitiveType == void.class)
404: return getVoidType();
405: return env.getTypeUtils().getPrimitiveType(
406: primitives.get(primitiveType));
407: }
408:
409: /**
410: * see {@link #ref(Class)}.
411: */
412: private static final TypeMirror DUMMY = new TypeMirror() {
413: public void accept(TypeVisitor v) {
414: throw new IllegalStateException();
415: }
416: };
417:
418: /**
419: * Implements {@link #getBaseClass}.
420: */
421: private final APTTypeVisitor<TypeMirror, TypeDeclaration> baseClassFinder = new APTTypeVisitor<TypeMirror, TypeDeclaration>() {
422: public TypeMirror onClassType(ClassType type,
423: TypeDeclaration sup) {
424: TypeMirror r = onDeclaredType(type, sup);
425: if (r != null)
426: return r;
427:
428: // otherwise recursively apply super class and base types
429: if (type.getSuperclass() != null) {
430: r = onClassType(type.getSuperclass(), sup);
431: if (r != null)
432: return r;
433: }
434:
435: return null;
436: }
437:
438: protected TypeMirror onPrimitiveType(PrimitiveType type,
439: TypeDeclaration param) {
440: return type;
441: }
442:
443: protected TypeMirror onVoidType(VoidType type,
444: TypeDeclaration param) {
445: return type;
446: }
447:
448: public TypeMirror onInterfaceType(InterfaceType type,
449: TypeDeclaration sup) {
450: return onDeclaredType(type, sup);
451: }
452:
453: private TypeMirror onDeclaredType(DeclaredType t,
454: TypeDeclaration sup) {
455: // t = sup<...>
456: if (t.getDeclaration().equals(sup))
457: return t;
458:
459: for (InterfaceType i : t.getSuperinterfaces()) {
460: TypeMirror r = onInterfaceType(i, sup);
461: if (r != null)
462: return r;
463: }
464:
465: return null;
466: }
467:
468: public TypeMirror onTypeVariable(TypeVariable t,
469: TypeDeclaration sup) {
470: // we are checking if T (declared as T extends A&B&C) is assignable to sup.
471: // so apply bounds recursively.
472: for (ReferenceType r : t.getDeclaration().getBounds()) {
473: TypeMirror m = apply(r, sup);
474: if (m != null)
475: return m;
476: }
477: return null;
478: }
479:
480: public TypeMirror onArrayType(ArrayType type,
481: TypeDeclaration sup) {
482: // we are checking if t=T[] is assignable to sup.
483: // the only case this is allowed is sup=Object,
484: // and Object isn't parameterized.
485: return null;
486: }
487:
488: public TypeMirror onWildcard(WildcardType type,
489: TypeDeclaration sup) {
490: // we are checking if T (= ? extends A&B&C) is assignable to sup.
491: // so apply bounds recursively.
492: for (ReferenceType r : type.getLowerBounds()) {
493: TypeMirror m = apply(r, sup);
494: if (m != null)
495: return m;
496: }
497: return null;
498: }
499: };
500:
501: public Location getClassLocation(TypeDeclaration decl) {
502: return getLocation(decl.getQualifiedName(), decl.getPosition());
503: }
504:
505: public Location getFieldLocation(FieldDeclaration decl) {
506: return getLocation(decl);
507: }
508:
509: public Location getMethodLocation(MethodDeclaration decl) {
510: return getLocation(decl);
511: }
512:
513: public boolean hasDefaultConstructor(TypeDeclaration t) {
514: if (!(t instanceof ClassDeclaration))
515: return false;
516:
517: ClassDeclaration c = (ClassDeclaration) t;
518: for (ConstructorDeclaration init : c.getConstructors()) {
519: if (init.getParameters().isEmpty())
520: return true;
521: }
522: return false;
523: }
524:
525: public boolean isStaticField(FieldDeclaration f) {
526: return hasModifier(f, Modifier.STATIC);
527: }
528:
529: public boolean isPublicMethod(MethodDeclaration m) {
530: return hasModifier(m, Modifier.PUBLIC);
531: }
532:
533: public boolean isPublicField(FieldDeclaration f) {
534: return hasModifier(f, Modifier.PUBLIC);
535: }
536:
537: public boolean isEnum(TypeDeclaration t) {
538: return t instanceof EnumDeclaration;
539: }
540:
541: private Location getLocation(MemberDeclaration decl) {
542: return getLocation(decl.getDeclaringType().getQualifiedName()
543: + '.' + decl.getSimpleName(), decl.getPosition());
544: }
545:
546: private Location getLocation(final String name,
547: final SourcePosition sp) {
548: return new Location() {
549: public String toString() {
550: if (sp == null)
551: return name + " (Unknown Source)";
552: // just like stack trace, we just print the file name and
553: // not the whole path. The idea is that the pakage name should
554: // provide enough clue on which directory it lives.
555: return name + '(' + sp.file().getName() + ':'
556: + sp.line() + ')';
557: }
558: };
559: }
560:
561: /**
562: * Comparator that uses the source position
563: */
564: private static final Comparator<Declaration> SOURCE_POS_COMPARATOR = new Comparator<Declaration>() {
565: public int compare(Declaration d1, Declaration d2) {
566: if (d1 == d2)
567: return 0;
568:
569: SourcePosition p1 = d1.getPosition();
570: SourcePosition p2 = d2.getPosition();
571:
572: if (p1 == null) {
573: return (p2 == null) ? 0 : 1;
574: } else {
575: if (p2 == null)
576: return -1;
577:
578: int fileComp = p1.file().compareTo(p2.file());
579: if (fileComp == 0) {
580: long diff = (long) p1.line() - (long) p2.line();
581: if (diff == 0) {
582: diff = Long.signum((long) p1.column()
583: - (long) p2.column());
584: if (diff != 0)
585: return (int) diff;
586: else {
587: // declarations may be two
588: // compiler-generated members with the
589: // same source position
590: return (Long.signum((long) System
591: .identityHashCode(d1)
592: - (long) System
593: .identityHashCode(d2)));
594: }
595: } else
596: return (diff < 0) ? -1 : 1;
597: } else
598: return fileComp;
599: }
600: }
601: };
602: }
|