1/* 2 * Copyright (c) 1997, 2015, Oracle and/or its affiliates. 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. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26package com.sun.tools.internal.jxc.model.nav; 27 28import com.sun.source.tree.CompilationUnitTree; 29import com.sun.source.util.TreePath; 30import com.sun.source.util.Trees; 31import com.sun.xml.internal.bind.v2.model.nav.Navigator; 32import com.sun.xml.internal.bind.v2.runtime.Location; 33import java.lang.annotation.Annotation; 34import java.util.ArrayList; 35import java.util.Collection; 36import java.util.HashMap; 37import java.util.List; 38import java.util.Map; 39import javax.annotation.processing.ProcessingEnvironment; 40import javax.lang.model.element.AnnotationMirror; 41import javax.lang.model.element.Element; 42import javax.lang.model.element.ElementKind; 43import javax.lang.model.element.ExecutableElement; 44import javax.lang.model.element.Modifier; 45import javax.lang.model.element.TypeElement; 46import javax.lang.model.element.TypeParameterElement; 47import javax.lang.model.element.VariableElement; 48import javax.lang.model.type.ArrayType; 49import javax.lang.model.type.DeclaredType; 50import javax.lang.model.type.PrimitiveType; 51import javax.lang.model.type.TypeKind; 52import javax.lang.model.type.TypeMirror; 53import javax.lang.model.type.TypeVariable; 54import javax.lang.model.type.TypeVisitor; 55import javax.lang.model.type.WildcardType; 56import javax.lang.model.util.ElementFilter; 57import javax.lang.model.util.Elements; 58import javax.lang.model.util.SimpleTypeVisitor6; 59import javax.lang.model.util.Types; 60 61/** 62 * {@link Navigator} implementation for annotation processing. 63 * TODO: check the spec on how generics are supposed to be handled 64 * 65 * @author Kohsuke Kawaguchi (kk@kohsuke.org) 66 */ 67public final class ApNavigator implements Navigator<TypeMirror, TypeElement, VariableElement, ExecutableElement> { 68 69 private final ProcessingEnvironment env; 70 71 private final PrimitiveType primitiveByte; 72 73 public ApNavigator(ProcessingEnvironment env) { 74 this.env = env; 75 this.primitiveByte = env.getTypeUtils().getPrimitiveType(TypeKind.BYTE); 76 } 77 78 public TypeElement getSuperClass(TypeElement typeElement) { 79 if (typeElement.getKind().equals(ElementKind.CLASS)) { 80 TypeMirror sup = typeElement.getSuperclass(); 81 if (!sup.getKind().equals(TypeKind.NONE)) 82 return (TypeElement) ((DeclaredType) sup).asElement(); 83 else 84 return null; 85 } 86 return env.getElementUtils().getTypeElement(Object.class.getName()); 87 } 88 89 public TypeMirror getBaseClass(TypeMirror type, TypeElement sup) { 90 return baseClassFinder.visit(type, sup); 91 } 92 93 public String getClassName(TypeElement t) { 94 return t.getQualifiedName().toString(); 95 } 96 97 public String getTypeName(TypeMirror typeMirror) { 98 return typeMirror.toString(); 99 } 100 101 public String getClassShortName(TypeElement t) { 102 return t.getSimpleName().toString(); 103 } 104 105 public Collection<VariableElement> getDeclaredFields(TypeElement typeElement) { 106 return ElementFilter.fieldsIn(typeElement.getEnclosedElements()); 107 } 108 109 public VariableElement getDeclaredField(TypeElement clazz, String fieldName) { 110 for (VariableElement fd : ElementFilter.fieldsIn(clazz.getEnclosedElements())) { 111 if (fd.getSimpleName().toString().equals(fieldName)) 112 return fd; 113 } 114 return null; 115 } 116 117 public Collection<ExecutableElement> getDeclaredMethods(TypeElement typeElement) { 118 return ElementFilter.methodsIn(typeElement.getEnclosedElements()); 119 } 120 121 public TypeElement getDeclaringClassForField(VariableElement f) { 122 return (TypeElement) f.getEnclosingElement(); 123 } 124 125 public TypeElement getDeclaringClassForMethod(ExecutableElement m) { 126 return (TypeElement) m.getEnclosingElement(); 127 } 128 129 public TypeMirror getFieldType(VariableElement f) { 130 return f.asType(); 131 } 132 133 public String getFieldName(VariableElement f) { 134 return f.getSimpleName().toString(); 135 } 136 137 public String getMethodName(ExecutableElement m) { 138 return m.getSimpleName().toString(); 139 } 140 141 public TypeMirror getReturnType(ExecutableElement m) { 142 return m.getReturnType(); 143 } 144 145 public TypeMirror[] getMethodParameters(ExecutableElement m) { 146 Collection<? extends VariableElement> ps = m.getParameters(); 147 TypeMirror[] r = new TypeMirror[ps.size()]; 148 int i=0; 149 for (VariableElement p : ps) 150 r[i++] = p.asType(); 151 return r; 152 } 153 154 public boolean isStaticMethod(ExecutableElement m) { 155 return hasModifier(m, Modifier.STATIC); 156 } 157 158 public boolean isFinalMethod(ExecutableElement m) { 159 return hasModifier(m, Modifier.FINAL); 160 } 161 162 private boolean hasModifier(Element d, Modifier mod) { 163 return d.getModifiers().contains(mod); 164 } 165 166 public boolean isSubClassOf(TypeMirror sub, TypeMirror sup) { 167 if(sup==DUMMY) 168 // see ref(). if the sub type is known to Annotation Processing, 169 // its base class must be known. Thus if the sup is DUMMY, 170 // it cannot possibly be the super type. 171 return false; 172 return env.getTypeUtils().isSubtype(sub,sup); 173 } 174 175 private String getSourceClassName(Class clazz) { 176 Class<?> d = clazz.getDeclaringClass(); 177 if(d==null) 178 return clazz.getName(); 179 else { 180 String shortName = clazz.getName().substring(d.getName().length()+1/*for $*/); 181 return getSourceClassName(d)+'.'+shortName; 182 } 183 } 184 185 public TypeMirror ref(Class c) { 186 if(c.isArray()) 187 return env.getTypeUtils().getArrayType( ref(c.getComponentType()) ); 188 if(c.isPrimitive()) 189 return getPrimitive(c); 190 TypeElement t = env.getElementUtils().getTypeElement(getSourceClassName(c)); 191 // Annotation Processing only operates on a set of classes used in the compilation, 192 // and it won't recognize additional classes (even if they are visible from javac) 193 // and return null. 194 // 195 // this is causing a problem where we check if a type is collection. 196 // so until the problem is fixed in Annotation Processing, work around the issue 197 // by returning a dummy token 198 // TODO: check if this is still valid 199 if(t==null) 200 return DUMMY; 201 return env.getTypeUtils().getDeclaredType(t); 202 } 203 204 public TypeMirror use(TypeElement t) { 205 assert t != null; 206 return env.getTypeUtils().getDeclaredType(t); 207 } 208 209 public TypeElement asDecl(TypeMirror m) { 210 m = env.getTypeUtils().erasure(m); 211 if (m.getKind().equals(TypeKind.DECLARED)) { 212 DeclaredType d = (DeclaredType) m; 213 return (TypeElement) d.asElement(); 214 } else 215 return null; 216 } 217 218 public TypeElement asDecl(Class c) { 219 return env.getElementUtils().getTypeElement(getSourceClassName(c)); 220 } 221 222 public TypeMirror erasure(TypeMirror t) { 223 Types tu = env.getTypeUtils(); 224 t = tu.erasure(t); 225 if (t.getKind().equals(TypeKind.DECLARED)) { 226 DeclaredType dt = (DeclaredType)t; 227 if (!dt.getTypeArguments().isEmpty()) 228 return tu.getDeclaredType((TypeElement) dt.asElement()); 229 } 230 return t; 231 } 232 233 public boolean isAbstract(TypeElement clazz) { 234 return hasModifier(clazz,Modifier.ABSTRACT); 235 } 236 237 public boolean isFinal(TypeElement clazz) { 238 return hasModifier(clazz, Modifier.FINAL); 239 } 240 241 public VariableElement[] getEnumConstants(TypeElement clazz) { 242 List<? extends Element> elements = env.getElementUtils().getAllMembers(clazz); 243 Collection<VariableElement> constants = new ArrayList<VariableElement>(); 244 for (Element element : elements) { 245 if (element.getKind().equals(ElementKind.ENUM_CONSTANT)) { 246 constants.add((VariableElement) element); 247 } 248 } 249 return constants.toArray(new VariableElement[constants.size()]); 250 } 251 252 public TypeMirror getVoidType() { 253 return env.getTypeUtils().getNoType(TypeKind.VOID); 254 } 255 256 public String getPackageName(TypeElement clazz) { 257 return env.getElementUtils().getPackageOf(clazz).getQualifiedName().toString(); 258 } 259 260 @Override 261 public TypeElement loadObjectFactory(TypeElement referencePoint, String packageName) { 262 return env.getElementUtils().getTypeElement(packageName + ".ObjectFactory"); 263 } 264 265 public boolean isBridgeMethod(ExecutableElement method) { 266 return method.getModifiers().contains(Modifier.VOLATILE); 267 } 268 269 public boolean isOverriding(ExecutableElement method, TypeElement base) { 270 Elements elements = env.getElementUtils(); 271 272 while (true) { 273 for (ExecutableElement m : ElementFilter.methodsIn(elements.getAllMembers(base))) { 274 if (elements.overrides(method, m, base)) 275 return true; 276 } 277 278 if (base.getSuperclass().getKind().equals(TypeKind.NONE)) 279 return false; 280 base = (TypeElement) env.getTypeUtils().asElement(base.getSuperclass()); 281 } 282 } 283 284 public boolean isInterface(TypeElement clazz) { 285 return clazz.getKind().isInterface(); 286 } 287 288 public boolean isTransient(VariableElement f) { 289 return f.getModifiers().contains(Modifier.TRANSIENT); 290 } 291 292 public boolean isInnerClass(TypeElement clazz) { 293 return clazz.getEnclosingElement() != null && !clazz.getModifiers().contains(Modifier.STATIC); 294 } 295 296 @Override 297 public boolean isSameType(TypeMirror t1, TypeMirror t2) { 298 return env.getTypeUtils().isSameType(t1, t2); 299 } 300 301 public boolean isArray(TypeMirror type) { 302 return type != null && type.getKind().equals(TypeKind.ARRAY); 303 } 304 305 public boolean isArrayButNotByteArray(TypeMirror t) { 306 if(!isArray(t)) 307 return false; 308 309 ArrayType at = (ArrayType) t; 310 TypeMirror ct = at.getComponentType(); 311 312 return !ct.equals(primitiveByte); 313 } 314 315 public TypeMirror getComponentType(TypeMirror t) { 316 if (isArray(t)) { 317 ArrayType at = (ArrayType) t; 318 return at.getComponentType(); 319 } 320 321 throw new IllegalArgumentException(); 322 } 323 324 public TypeMirror getTypeArgument(TypeMirror typeMirror, int i) { 325 if (typeMirror != null && typeMirror.getKind().equals(TypeKind.DECLARED)) { 326 DeclaredType declaredType = (DeclaredType) typeMirror; 327 TypeMirror[] args = declaredType.getTypeArguments().toArray(new TypeMirror[declaredType.getTypeArguments().size()]); 328 return args[i]; 329 } else throw new IllegalArgumentException(); 330 } 331 332 public boolean isParameterizedType(TypeMirror typeMirror) { 333 if (typeMirror != null && typeMirror.getKind().equals(TypeKind.DECLARED)) { 334 DeclaredType d = (DeclaredType) typeMirror; 335 return !d.getTypeArguments().isEmpty(); 336 } 337 return false; 338 } 339 340 public boolean isPrimitive(TypeMirror t) { 341 return t.getKind().isPrimitive(); 342 } 343 344 private static final Map<Class, TypeKind> primitives = new HashMap<Class, TypeKind>(); 345 346 static { 347 primitives.put(Integer.TYPE, TypeKind.INT); 348 primitives.put(Byte.TYPE, TypeKind.BYTE); 349 primitives.put(Float.TYPE, TypeKind.FLOAT); 350 primitives.put(Boolean.TYPE, TypeKind.BOOLEAN); 351 primitives.put(Short.TYPE, TypeKind.SHORT); 352 primitives.put(Long.TYPE, TypeKind.LONG); 353 primitives.put(Double.TYPE, TypeKind.DOUBLE); 354 primitives.put(Character.TYPE, TypeKind.CHAR); 355 } 356 357 public TypeMirror getPrimitive(Class primitiveType) { 358 assert primitiveType.isPrimitive(); 359 if(primitiveType==void.class) 360 return getVoidType(); 361 return env.getTypeUtils().getPrimitiveType(primitives.get(primitiveType)); 362 } 363 364 /** 365 * see {@link #ref(Class)}. 366 */ 367 private static final TypeMirror DUMMY = new TypeMirror() { 368 @Override 369 public <R, P> R accept(TypeVisitor<R, P> v, P p) { 370 throw new IllegalStateException(); 371 } 372 373 @Override 374 public TypeKind getKind() { 375 throw new IllegalStateException(); 376 } 377 378// @Override 379 public List<? extends AnnotationMirror> getAnnotationMirrors() { 380 throw new IllegalStateException(); 381 } 382 383// @Override 384 public <A extends Annotation> A getAnnotation(Class<A> annotationType) { 385 throw new IllegalStateException(); 386 } 387 388// @Override 389 public <A extends Annotation> A[] getAnnotationsByType(Class<A> annotationType) { 390 throw new IllegalStateException(); 391 } 392 }; 393 394 public Location getClassLocation(TypeElement typeElement) { 395 Trees trees = Trees.instance(env); 396 return getLocation(typeElement.getQualifiedName().toString(), trees.getPath(typeElement)); 397 } 398 399 public Location getFieldLocation(VariableElement variableElement) { 400 return getLocation(variableElement); 401 } 402 403 public Location getMethodLocation(ExecutableElement executableElement) { 404 return getLocation(executableElement); 405 } 406 407 public boolean hasDefaultConstructor(TypeElement t) { 408 if (t == null || !t.getKind().equals(ElementKind.CLASS)) 409 return false; 410 411 for (ExecutableElement init : ElementFilter.constructorsIn(env.getElementUtils().getAllMembers(t))) { 412 if (init.getParameters().isEmpty()) 413 return true; 414 } 415 return false; 416 } 417 418 public boolean isStaticField(VariableElement f) { 419 return hasModifier(f,Modifier.STATIC); 420 } 421 422 public boolean isPublicMethod(ExecutableElement m) { 423 return hasModifier(m,Modifier.PUBLIC); 424 } 425 426 public boolean isPublicField(VariableElement f) { 427 return hasModifier(f,Modifier.PUBLIC); 428 } 429 430 public boolean isEnum(TypeElement t) { 431 return t != null && t.getKind().equals(ElementKind.ENUM); 432 } 433 434 private Location getLocation(Element element) { 435 Trees trees = Trees.instance(env); 436 return getLocation( 437 ((TypeElement) element.getEnclosingElement()).getQualifiedName() + "." + element.getSimpleName(), 438 trees.getPath(element) 439 ); 440 } 441 442 private Location getLocation(final String name, final TreePath treePath) { 443 return new Location() { 444 public String toString() { 445 if (treePath == null) 446 return name + " (Unknown Source)"; 447 // just like stack trace, we just print the file name and 448 // not the whole path. The idea is that the package name should 449 // provide enough clue on which directory it lives. 450 CompilationUnitTree compilationUnit = treePath.getCompilationUnit(); 451 Trees trees = Trees.instance(env); 452 long startPosition = trees.getSourcePositions().getStartPosition(compilationUnit, treePath.getLeaf()); 453 return name + "(" + 454 compilationUnit.getSourceFile().getName() + ":" + compilationUnit.getLineMap().getLineNumber(startPosition) + 455 ")"; 456 } 457 }; 458 } 459 460 /** 461 * Implements {@link #getBaseClass}. 462 */ 463 private final SimpleTypeVisitor6<TypeMirror, TypeElement> baseClassFinder = new SimpleTypeVisitor6<TypeMirror, TypeElement>() { 464 @Override 465 public TypeMirror visitDeclared(DeclaredType t, TypeElement sup) { 466 if (t.asElement().equals(sup)) 467 return t; 468 469 for (TypeMirror i : env.getTypeUtils().directSupertypes(t)) { 470 TypeMirror r = visitDeclared((DeclaredType) i, sup); 471 if (r != null) 472 return r; 473 } 474 475 // otherwise recursively apply super class and base types 476 TypeMirror superclass = ((TypeElement) t.asElement()).getSuperclass(); 477 if (!superclass.getKind().equals(TypeKind.NONE)) { 478 TypeMirror r = visitDeclared((DeclaredType) superclass, sup); 479 if (r != null) 480 return r; 481 } 482 return null; 483 } 484 485 @Override 486 public TypeMirror visitTypeVariable(TypeVariable t, TypeElement typeElement) { 487 // we are checking if T (declared as T extends A&B&C) is assignable to sup. 488 // so apply bounds recursively. 489 for (TypeMirror typeMirror : ((TypeParameterElement) t.asElement()).getBounds()) { 490 TypeMirror m = visit(typeMirror, typeElement); 491 if (m != null) 492 return m; 493 } 494 return null; 495 } 496 497 @Override 498 public TypeMirror visitArray(ArrayType t, TypeElement typeElement) { 499 // we are checking if t=T[] is assignable to sup. 500 // the only case this is allowed is sup=Object, 501 // and Object isn't parameterized. 502 return null; 503 } 504 505 @Override 506 public TypeMirror visitWildcard(WildcardType t, TypeElement typeElement) { 507 // we are checking if T (= ? extends A&B&C) is assignable to sup. 508 // so apply bounds recursively. 509 return visit(t.getExtendsBound(), typeElement); 510 } 511 512 @Override 513 protected TypeMirror defaultAction(TypeMirror e, TypeElement typeElement) { 514 return e; 515 } 516 }; 517} 518