Mercurial > hg > graal-compiler
comparison graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/ElementUtils.java @ 16759:23415229349b
Truffle-DSL: new package structure.
author | Christian Humer <christian.humer@gmail.com> |
---|---|
date | Mon, 11 Aug 2014 15:57:14 +0200 |
parents | graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/Utils.java@bd28da642eea |
children | 89f635cbd85e |
comparison
equal
deleted
inserted
replaced
16758:c5f8eeb3cbc8 | 16759:23415229349b |
---|---|
1 /* | |
2 * Copyright (c) 2012, 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. | |
8 * | |
9 * This code is distributed in the hope that it will be useful, but WITHOUT | |
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
12 * version 2 for more details (a copy is included in the LICENSE file that | |
13 * accompanied this code). | |
14 * | |
15 * You should have received a copy of the GNU General Public License version | |
16 * 2 along with this work; if not, write to the Free Software Foundation, | |
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
18 * | |
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
20 * or visit www.oracle.com if you need additional information or have any | |
21 * questions. | |
22 */ | |
23 package com.oracle.truffle.dsl.processor.java; | |
24 | |
25 import java.io.*; | |
26 import java.lang.annotation.*; | |
27 import java.util.*; | |
28 | |
29 import javax.annotation.processing.*; | |
30 import javax.lang.model.element.*; | |
31 import javax.lang.model.type.*; | |
32 import javax.lang.model.util.*; | |
33 | |
34 import com.oracle.truffle.dsl.processor.*; | |
35 import com.oracle.truffle.dsl.processor.java.model.*; | |
36 import com.oracle.truffle.dsl.processor.java.model.CodeTypeMirror.DeclaredCodeTypeMirror; | |
37 | |
38 /** | |
39 * THIS IS NOT PUBLIC API. | |
40 */ | |
41 public class ElementUtils { | |
42 | |
43 public static ExecutableElement findExecutableElement(DeclaredType type, String name) { | |
44 List<? extends ExecutableElement> elements = ElementFilter.methodsIn(type.asElement().getEnclosedElements()); | |
45 for (ExecutableElement executableElement : elements) { | |
46 if (executableElement.getSimpleName().toString().equals(name)) { | |
47 return executableElement; | |
48 } | |
49 } | |
50 return null; | |
51 } | |
52 | |
53 public static boolean needsCastTo(TypeMirror sourceType, TypeMirror targetType) { | |
54 if (typeEquals(sourceType, targetType)) { | |
55 return false; | |
56 } else if (isObject(targetType)) { | |
57 return false; | |
58 } else if (isVoid(targetType)) { | |
59 return false; | |
60 } else if (isAssignable(sourceType, targetType)) { | |
61 return false; | |
62 } | |
63 return true; | |
64 } | |
65 | |
66 public static VariableElement findVariableElement(DeclaredType type, String name) { | |
67 List<? extends VariableElement> elements = ElementFilter.fieldsIn(type.asElement().getEnclosedElements()); | |
68 for (VariableElement variableElement : elements) { | |
69 if (variableElement.getSimpleName().toString().equals(name)) { | |
70 return variableElement; | |
71 } | |
72 } | |
73 return null; | |
74 } | |
75 | |
76 public static TypeMirror boxType(ProcessorContext context, TypeMirror primitiveType) { | |
77 TypeMirror boxedType = primitiveType; | |
78 if (boxedType.getKind().isPrimitive()) { | |
79 boxedType = context.getEnvironment().getTypeUtils().boxedClass((PrimitiveType) boxedType).asType(); | |
80 } | |
81 return boxedType; | |
82 } | |
83 | |
84 public static DeclaredType getDeclaredType(TypeElement typeElem, TypeMirror... typeArgs) { | |
85 return new DeclaredCodeTypeMirror(typeElem, Arrays.asList(typeArgs)); | |
86 } | |
87 | |
88 public static List<AnnotationMirror> collectAnnotations(ProcessorContext context, AnnotationMirror markerAnnotation, String elementName, Element element, | |
89 Class<? extends Annotation> annotationClass) { | |
90 List<AnnotationMirror> result = new ArrayList<>(); | |
91 if (markerAnnotation != null) { | |
92 result.addAll(ElementUtils.getAnnotationValueList(AnnotationMirror.class, markerAnnotation, elementName)); | |
93 } | |
94 AnnotationMirror explicit = ElementUtils.findAnnotationMirror(context.getEnvironment(), element, annotationClass); | |
95 if (explicit != null) { | |
96 result.add(explicit); | |
97 } | |
98 return result; | |
99 } | |
100 | |
101 public static TypeMirror getCommonSuperType(ProcessorContext context, TypeMirror[] types) { | |
102 if (types.length == 0) { | |
103 return context.getType(Object.class); | |
104 } | |
105 TypeMirror prev = types[0]; | |
106 for (int i = 1; i < types.length; i++) { | |
107 prev = getCommonSuperType(context, prev, types[i]); | |
108 } | |
109 return prev; | |
110 } | |
111 | |
112 private static TypeMirror getCommonSuperType(ProcessorContext context, TypeMirror type1, TypeMirror type2) { | |
113 if (typeEquals(type1, type2)) { | |
114 return type1; | |
115 } | |
116 TypeElement element1 = fromTypeMirror(type1); | |
117 TypeElement element2 = fromTypeMirror(type2); | |
118 if (element1 == null || element2 == null) { | |
119 return context.getType(Object.class); | |
120 } | |
121 | |
122 List<TypeElement> element1Types = getDirectSuperTypes(element1); | |
123 element1Types.add(0, element1); | |
124 List<TypeElement> element2Types = getDirectSuperTypes(element2); | |
125 element2Types.add(0, element2); | |
126 | |
127 for (TypeElement superType1 : element1Types) { | |
128 for (TypeElement superType2 : element2Types) { | |
129 if (typeEquals(superType1.asType(), superType2.asType())) { | |
130 return superType2.asType(); | |
131 } | |
132 } | |
133 } | |
134 return context.getType(Object.class); | |
135 } | |
136 | |
137 public static String getReadableSignature(ExecutableElement method) { | |
138 // TODO toString does not guarantee a good signature | |
139 return method.toString(); | |
140 } | |
141 | |
142 public static boolean hasError(TypeMirror mirror) { | |
143 switch (mirror.getKind()) { | |
144 case BOOLEAN: | |
145 case BYTE: | |
146 case CHAR: | |
147 case DOUBLE: | |
148 case FLOAT: | |
149 case INT: | |
150 case SHORT: | |
151 case LONG: | |
152 case DECLARED: | |
153 case VOID: | |
154 case TYPEVAR: | |
155 return false; | |
156 case ARRAY: | |
157 return hasError(((ArrayType) mirror).getComponentType()); | |
158 case ERROR: | |
159 return true; | |
160 default: | |
161 throw new RuntimeException("Unknown type specified " + mirror.getKind() + " mirror: " + mirror); | |
162 } | |
163 } | |
164 | |
165 public static boolean isSubtype(TypeMirror type1, TypeMirror type2) { | |
166 if (type1 instanceof CodeTypeMirror && type2 instanceof CodeTypeMirror) { | |
167 throw new UnsupportedOperationException(); | |
168 } | |
169 return ProcessorContext.getInstance().getEnvironment().getTypeUtils().isSubtype(type1, type2); | |
170 } | |
171 | |
172 public static boolean isAssignable(TypeMirror from, TypeMirror to) { | |
173 ProcessorContext context = ProcessorContext.getInstance(); | |
174 | |
175 if (!(from instanceof CodeTypeMirror) && !(to instanceof CodeTypeMirror)) { | |
176 return context.getEnvironment().getTypeUtils().isAssignable(context.reloadType(from), context.reloadType(to)); | |
177 } else { | |
178 return isAssignableImpl(from, to); | |
179 } | |
180 } | |
181 | |
182 private static boolean isAssignableImpl(TypeMirror from, TypeMirror to) { | |
183 // JLS 5.1.1 identity conversion | |
184 if (ElementUtils.typeEquals(from, to)) { | |
185 return true; | |
186 } | |
187 | |
188 if (isObject(to)) { | |
189 return true; | |
190 } | |
191 | |
192 // JLS 5.1.2 widening primitives | |
193 if (ElementUtils.isPrimitive(from) && ElementUtils.isPrimitive(to)) { | |
194 TypeKind fromKind = from.getKind(); | |
195 TypeKind toKind = to.getKind(); | |
196 switch (fromKind) { | |
197 case BYTE: | |
198 switch (toKind) { | |
199 case SHORT: | |
200 case INT: | |
201 case LONG: | |
202 case FLOAT: | |
203 case DOUBLE: | |
204 return true; | |
205 } | |
206 break; | |
207 case SHORT: | |
208 switch (toKind) { | |
209 case INT: | |
210 case LONG: | |
211 case FLOAT: | |
212 case DOUBLE: | |
213 return true; | |
214 } | |
215 break; | |
216 case CHAR: | |
217 switch (toKind) { | |
218 case INT: | |
219 case LONG: | |
220 case FLOAT: | |
221 case DOUBLE: | |
222 return true; | |
223 } | |
224 break; | |
225 case INT: | |
226 switch (toKind) { | |
227 case LONG: | |
228 case FLOAT: | |
229 case DOUBLE: | |
230 return true; | |
231 } | |
232 break; | |
233 case LONG: | |
234 switch (toKind) { | |
235 case FLOAT: | |
236 case DOUBLE: | |
237 return true; | |
238 } | |
239 break; | |
240 case FLOAT: | |
241 switch (toKind) { | |
242 case DOUBLE: | |
243 return true; | |
244 } | |
245 break; | |
246 | |
247 } | |
248 return false; | |
249 } else if (ElementUtils.isPrimitive(from) || ElementUtils.isPrimitive(to)) { | |
250 return false; | |
251 } | |
252 | |
253 if (from instanceof ArrayType && to instanceof ArrayType) { | |
254 return isAssignable(((ArrayType) from).getComponentType(), ((ArrayType) to).getComponentType()); | |
255 } | |
256 | |
257 if (from instanceof ArrayType || to instanceof ArrayType) { | |
258 return false; | |
259 } | |
260 | |
261 TypeElement fromType = ElementUtils.fromTypeMirror(from); | |
262 TypeElement toType = ElementUtils.fromTypeMirror(to); | |
263 if (fromType == null || toType == null) { | |
264 return false; | |
265 } | |
266 // JLS 5.1.6 narrowing reference conversion | |
267 | |
268 List<TypeElement> superTypes = ElementUtils.getSuperTypes(fromType); | |
269 for (TypeElement superType : superTypes) { | |
270 if (ElementUtils.typeEquals(superType.asType(), to)) { | |
271 return true; | |
272 } | |
273 } | |
274 | |
275 // TODO more spec | |
276 return false; | |
277 } | |
278 | |
279 public static Set<Modifier> modifiers(Modifier... modifier) { | |
280 return new LinkedHashSet<>(Arrays.asList(modifier)); | |
281 } | |
282 | |
283 public static String getTypeId(TypeMirror mirror) { | |
284 switch (mirror.getKind()) { | |
285 case BOOLEAN: | |
286 return "Boolean"; | |
287 case BYTE: | |
288 return "Byte"; | |
289 case CHAR: | |
290 return "Char"; | |
291 case DOUBLE: | |
292 return "Double"; | |
293 case FLOAT: | |
294 return "Float"; | |
295 case SHORT: | |
296 return "Short"; | |
297 case INT: | |
298 return "Int"; | |
299 case LONG: | |
300 return "Long"; | |
301 case DECLARED: | |
302 return fixECJBinaryNameIssue(((DeclaredType) mirror).asElement().getSimpleName().toString()); | |
303 case ARRAY: | |
304 return getTypeId(((ArrayType) mirror).getComponentType()) + "Array"; | |
305 case VOID: | |
306 return "Void"; | |
307 case WILDCARD: | |
308 StringBuilder b = new StringBuilder(); | |
309 WildcardType type = (WildcardType) mirror; | |
310 if (type.getExtendsBound() != null) { | |
311 b.append("Extends").append(getTypeId(type.getExtendsBound())); | |
312 } else if (type.getSuperBound() != null) { | |
313 b.append("Super").append(getTypeId(type.getExtendsBound())); | |
314 } | |
315 return b.toString(); | |
316 case TYPEVAR: | |
317 return "Any"; | |
318 case ERROR: | |
319 throw new CompileErrorException("Type error " + mirror); | |
320 default: | |
321 throw new RuntimeException("Unknown type specified " + mirror.getKind() + " mirror: " + mirror); | |
322 } | |
323 } | |
324 | |
325 public static String getSimpleName(TypeElement element) { | |
326 return getSimpleName(element.asType()); | |
327 } | |
328 | |
329 public static String getSimpleName(TypeMirror mirror) { | |
330 switch (mirror.getKind()) { | |
331 case BOOLEAN: | |
332 return "boolean"; | |
333 case BYTE: | |
334 return "byte"; | |
335 case CHAR: | |
336 return "char"; | |
337 case DOUBLE: | |
338 return "double"; | |
339 case FLOAT: | |
340 return "float"; | |
341 case SHORT: | |
342 return "short"; | |
343 case INT: | |
344 return "int"; | |
345 case LONG: | |
346 return "long"; | |
347 case DECLARED: | |
348 return getDeclaredName((DeclaredType) mirror); | |
349 case ARRAY: | |
350 return getSimpleName(((ArrayType) mirror).getComponentType()) + "[]"; | |
351 case VOID: | |
352 return "void"; | |
353 case WILDCARD: | |
354 return getWildcardName((WildcardType) mirror); | |
355 case TYPEVAR: | |
356 return "?"; | |
357 case ERROR: | |
358 throw new CompileErrorException("Type error " + mirror); | |
359 default: | |
360 throw new RuntimeException("Unknown type specified " + mirror.getKind() + " mirror: " + mirror); | |
361 } | |
362 } | |
363 | |
364 private static String getWildcardName(WildcardType type) { | |
365 StringBuilder b = new StringBuilder(); | |
366 if (type.getExtendsBound() != null) { | |
367 b.append("? extends ").append(getSimpleName(type.getExtendsBound())); | |
368 } else if (type.getSuperBound() != null) { | |
369 b.append("? super ").append(getSimpleName(type.getExtendsBound())); | |
370 } | |
371 return b.toString(); | |
372 } | |
373 | |
374 private static String getDeclaredName(DeclaredType element) { | |
375 String simpleName = fixECJBinaryNameIssue(element.asElement().getSimpleName().toString()); | |
376 | |
377 if (element.getTypeArguments().size() == 0) { | |
378 return simpleName; | |
379 } | |
380 | |
381 StringBuilder b = new StringBuilder(simpleName); | |
382 b.append("<"); | |
383 if (element.getTypeArguments().size() > 0) { | |
384 for (int i = 0; i < element.getTypeArguments().size(); i++) { | |
385 b.append(getSimpleName(element.getTypeArguments().get(i))); | |
386 if (i < element.getTypeArguments().size() - 1) { | |
387 b.append(", "); | |
388 } | |
389 } | |
390 } | |
391 b.append(">"); | |
392 return b.toString(); | |
393 } | |
394 | |
395 public static String fixECJBinaryNameIssue(String name) { | |
396 if (name.contains("$")) { | |
397 int lastIndex = name.lastIndexOf('$'); | |
398 return name.substring(lastIndex + 1, name.length()); | |
399 } | |
400 return name; | |
401 } | |
402 | |
403 public static String getQualifiedName(TypeElement element) { | |
404 String qualifiedName = element.getQualifiedName().toString(); | |
405 if (qualifiedName.contains("$")) { | |
406 /* | |
407 * If a class gets loaded in its binary form by the ECJ compiler it fails to produce the | |
408 * proper canonical class name. It leaves the $ in the qualified name of the class. So | |
409 * one instance of a TypeElement may be loaded in binary and one in source form. The | |
410 * current type comparison in #typeEquals compares by the qualified name so the | |
411 * qualified name must match. This is basically a hack to fix the returned qualified | |
412 * name of eclipse. | |
413 */ | |
414 qualifiedName = qualifiedName.replace('$', '.'); | |
415 } | |
416 return qualifiedName; | |
417 } | |
418 | |
419 public static String getQualifiedName(TypeMirror mirror) { | |
420 switch (mirror.getKind()) { | |
421 case BOOLEAN: | |
422 return "boolean"; | |
423 case BYTE: | |
424 return "byte"; | |
425 case CHAR: | |
426 return "char"; | |
427 case DOUBLE: | |
428 return "double"; | |
429 case SHORT: | |
430 return "short"; | |
431 case FLOAT: | |
432 return "float"; | |
433 case INT: | |
434 return "int"; | |
435 case LONG: | |
436 return "long"; | |
437 case DECLARED: | |
438 return getQualifiedName(fromTypeMirror(mirror)); | |
439 case ARRAY: | |
440 return getQualifiedName(((ArrayType) mirror).getComponentType()); | |
441 case VOID: | |
442 return "void"; | |
443 case TYPEVAR: | |
444 return getSimpleName(mirror); | |
445 case ERROR: | |
446 throw new CompileErrorException("Type error " + mirror); | |
447 case EXECUTABLE: | |
448 return ((ExecutableType) mirror).toString(); | |
449 case NONE: | |
450 return "$none"; | |
451 default: | |
452 throw new RuntimeException("Unknown type specified " + mirror + " mirror: " + mirror); | |
453 } | |
454 } | |
455 | |
456 public static boolean isVoid(TypeMirror mirror) { | |
457 return mirror != null && mirror.getKind() == TypeKind.VOID; | |
458 } | |
459 | |
460 public static boolean isPrimitive(TypeMirror mirror) { | |
461 return mirror != null && mirror.getKind().isPrimitive(); | |
462 } | |
463 | |
464 public static List<String> getQualifiedSuperTypeNames(TypeElement element) { | |
465 List<TypeElement> types = getSuperTypes(element); | |
466 List<String> qualifiedNames = new ArrayList<>(); | |
467 for (TypeElement type : types) { | |
468 qualifiedNames.add(getQualifiedName(type)); | |
469 } | |
470 return qualifiedNames; | |
471 } | |
472 | |
473 public static List<TypeElement> getDeclaredTypes(TypeElement element) { | |
474 return ElementFilter.typesIn(element.getEnclosedElements()); | |
475 } | |
476 | |
477 public static boolean isEnclosedIn(Element enclosedIn, Element element) { | |
478 if (element == null) { | |
479 return false; | |
480 } else if (enclosedIn.equals(element)) { | |
481 return true; | |
482 } else { | |
483 return isEnclosedIn(enclosedIn, element.getEnclosingElement()); | |
484 } | |
485 } | |
486 | |
487 public static TypeElement findRootEnclosingType(Element element) { | |
488 List<Element> elements = getElementHierarchy(element); | |
489 | |
490 for (int i = elements.size() - 1; i >= 0; i--) { | |
491 if (elements.get(i).getKind().isClass()) { | |
492 return (TypeElement) elements.get(i); | |
493 } | |
494 } | |
495 | |
496 return null; | |
497 } | |
498 | |
499 public static List<Element> getElementHierarchy(Element e) { | |
500 List<Element> elements = new ArrayList<>(); | |
501 elements.add(e); | |
502 | |
503 Element enclosing = e.getEnclosingElement(); | |
504 while (enclosing != null && enclosing.getKind() != ElementKind.PACKAGE) { | |
505 elements.add(enclosing); | |
506 enclosing = enclosing.getEnclosingElement(); | |
507 } | |
508 if (enclosing != null) { | |
509 elements.add(enclosing); | |
510 } | |
511 return elements; | |
512 } | |
513 | |
514 public static TypeElement findNearestEnclosingType(Element element) { | |
515 List<Element> elements = getElementHierarchy(element); | |
516 for (Element e : elements) { | |
517 if (e.getKind().isClass()) { | |
518 return (TypeElement) e; | |
519 } | |
520 } | |
521 return null; | |
522 } | |
523 | |
524 public static List<TypeElement> getDirectSuperTypes(TypeElement element) { | |
525 List<TypeElement> types = new ArrayList<>(); | |
526 if (element.getSuperclass() != null) { | |
527 TypeElement superElement = fromTypeMirror(element.getSuperclass()); | |
528 if (superElement != null) { | |
529 types.add(superElement); | |
530 types.addAll(getDirectSuperTypes(superElement)); | |
531 } | |
532 } | |
533 | |
534 return types; | |
535 } | |
536 | |
537 public static List<TypeMirror> getAssignableTypes(ProcessorContext context, TypeMirror type) { | |
538 if (isPrimitive(type)) { | |
539 return Arrays.asList(type, boxType(context, type), context.getType(Object.class)); | |
540 } else if (type.getKind() == TypeKind.ARRAY) { | |
541 return Arrays.asList(type, context.getType(Object.class)); | |
542 } else if (type.getKind() == TypeKind.DECLARED) { | |
543 List<TypeElement> types = getSuperTypes(fromTypeMirror(type)); | |
544 List<TypeMirror> mirrors = new ArrayList<>(types.size()); | |
545 mirrors.add(type); | |
546 for (TypeElement typeElement : types) { | |
547 mirrors.add(typeElement.asType()); | |
548 } | |
549 return mirrors; | |
550 } else { | |
551 return Collections.emptyList(); | |
552 } | |
553 } | |
554 | |
555 public static List<TypeElement> getSuperTypes(TypeElement element) { | |
556 List<TypeElement> types = new ArrayList<>(); | |
557 List<TypeElement> superTypes = null; | |
558 List<TypeElement> superInterfaces = null; | |
559 if (element.getSuperclass() != null) { | |
560 TypeElement superElement = fromTypeMirror(element.getSuperclass()); | |
561 if (superElement != null) { | |
562 types.add(superElement); | |
563 superTypes = getSuperTypes(superElement); | |
564 } | |
565 } | |
566 for (TypeMirror interfaceMirror : element.getInterfaces()) { | |
567 TypeElement interfaceElement = fromTypeMirror(interfaceMirror); | |
568 if (interfaceElement != null) { | |
569 types.add(interfaceElement); | |
570 superInterfaces = getSuperTypes(interfaceElement); | |
571 } | |
572 } | |
573 | |
574 if (superTypes != null) { | |
575 types.addAll(superTypes); | |
576 } | |
577 | |
578 if (superInterfaces != null) { | |
579 types.addAll(superInterfaces); | |
580 } | |
581 | |
582 return types; | |
583 } | |
584 | |
585 public static String getPackageName(TypeElement element) { | |
586 return findPackageElement(element).getQualifiedName().toString(); | |
587 } | |
588 | |
589 public static String getPackageName(TypeMirror mirror) { | |
590 switch (mirror.getKind()) { | |
591 case BOOLEAN: | |
592 case BYTE: | |
593 case CHAR: | |
594 case DOUBLE: | |
595 case FLOAT: | |
596 case SHORT: | |
597 case INT: | |
598 case LONG: | |
599 case VOID: | |
600 case TYPEVAR: | |
601 return null; | |
602 case DECLARED: | |
603 PackageElement pack = findPackageElement(fromTypeMirror(mirror)); | |
604 if (pack == null) { | |
605 throw new IllegalArgumentException("No package element found for declared type " + getSimpleName(mirror)); | |
606 } | |
607 return pack.getQualifiedName().toString(); | |
608 case ARRAY: | |
609 return getSimpleName(((ArrayType) mirror).getComponentType()); | |
610 default: | |
611 throw new RuntimeException("Unknown type specified " + mirror.getKind()); | |
612 } | |
613 } | |
614 | |
615 public static String createConstantName(String simpleName) { | |
616 // TODO use camel case to produce underscores. | |
617 return simpleName.toString().toUpperCase(); | |
618 } | |
619 | |
620 public static TypeElement fromTypeMirror(TypeMirror mirror) { | |
621 switch (mirror.getKind()) { | |
622 case DECLARED: | |
623 return (TypeElement) ((DeclaredType) mirror).asElement(); | |
624 case ARRAY: | |
625 return fromTypeMirror(((ArrayType) mirror).getComponentType()); | |
626 default: | |
627 return null; | |
628 } | |
629 } | |
630 | |
631 @SuppressWarnings("unchecked") | |
632 public static <T> List<T> getAnnotationValueList(Class<T> expectedListType, AnnotationMirror mirror, String name) { | |
633 List<? extends AnnotationValue> values = getAnnotationValue(List.class, mirror, name); | |
634 List<T> result = new ArrayList<>(); | |
635 | |
636 if (values != null) { | |
637 for (AnnotationValue value : values) { | |
638 T annotationValue = resolveAnnotationValue(expectedListType, value); | |
639 if (annotationValue != null) { | |
640 result.add(annotationValue); | |
641 } | |
642 } | |
643 } | |
644 return result; | |
645 } | |
646 | |
647 public static <T> T getAnnotationValue(Class<T> expectedType, AnnotationMirror mirror, String name) { | |
648 return resolveAnnotationValue(expectedType, getAnnotationValue(mirror, name)); | |
649 } | |
650 | |
651 @SuppressWarnings({"unchecked"}) | |
652 private static <T> T resolveAnnotationValue(Class<T> expectedType, AnnotationValue value) { | |
653 if (value == null) { | |
654 return null; | |
655 } | |
656 | |
657 Object unboxedValue = value.accept(new AnnotationValueVisitorImpl(), null); | |
658 if (unboxedValue != null) { | |
659 if (expectedType == TypeMirror.class && unboxedValue instanceof String) { | |
660 return null; | |
661 } | |
662 if (!expectedType.isAssignableFrom(unboxedValue.getClass())) { | |
663 throw new ClassCastException(unboxedValue.getClass().getName() + " not assignable from " + expectedType.getName()); | |
664 } | |
665 } | |
666 return (T) unboxedValue; | |
667 } | |
668 | |
669 public static AnnotationValue getAnnotationValue(AnnotationMirror mirror, String name) { | |
670 ExecutableElement valueMethod = null; | |
671 for (ExecutableElement method : ElementFilter.methodsIn(mirror.getAnnotationType().asElement().getEnclosedElements())) { | |
672 if (method.getSimpleName().toString().equals(name)) { | |
673 valueMethod = method; | |
674 break; | |
675 } | |
676 } | |
677 | |
678 if (valueMethod == null) { | |
679 return null; | |
680 } | |
681 | |
682 AnnotationValue value = mirror.getElementValues().get(valueMethod); | |
683 if (value == null) { | |
684 value = valueMethod.getDefaultValue(); | |
685 } | |
686 | |
687 return value; | |
688 } | |
689 | |
690 private static class AnnotationValueVisitorImpl extends AbstractAnnotationValueVisitor7<Object, Void> { | |
691 | |
692 @Override | |
693 public Object visitBoolean(boolean b, Void p) { | |
694 return Boolean.valueOf(b); | |
695 } | |
696 | |
697 @Override | |
698 public Object visitByte(byte b, Void p) { | |
699 return Byte.valueOf(b); | |
700 } | |
701 | |
702 @Override | |
703 public Object visitChar(char c, Void p) { | |
704 return c; | |
705 } | |
706 | |
707 @Override | |
708 public Object visitDouble(double d, Void p) { | |
709 return d; | |
710 } | |
711 | |
712 @Override | |
713 public Object visitFloat(float f, Void p) { | |
714 return f; | |
715 } | |
716 | |
717 @Override | |
718 public Object visitInt(int i, Void p) { | |
719 return i; | |
720 } | |
721 | |
722 @Override | |
723 public Object visitLong(long i, Void p) { | |
724 return i; | |
725 } | |
726 | |
727 @Override | |
728 public Object visitShort(short s, Void p) { | |
729 return s; | |
730 } | |
731 | |
732 @Override | |
733 public Object visitString(String s, Void p) { | |
734 return s; | |
735 } | |
736 | |
737 @Override | |
738 public Object visitType(TypeMirror t, Void p) { | |
739 return t; | |
740 } | |
741 | |
742 @Override | |
743 public Object visitEnumConstant(VariableElement c, Void p) { | |
744 return c; | |
745 } | |
746 | |
747 @Override | |
748 public Object visitAnnotation(AnnotationMirror a, Void p) { | |
749 return a; | |
750 } | |
751 | |
752 @Override | |
753 public Object visitArray(List<? extends AnnotationValue> vals, Void p) { | |
754 return vals; | |
755 } | |
756 | |
757 } | |
758 | |
759 public static String printException(Throwable e) { | |
760 StringWriter string = new StringWriter(); | |
761 PrintWriter writer = new PrintWriter(string); | |
762 e.printStackTrace(writer); | |
763 writer.flush(); | |
764 return e.getMessage() + "\r\n" + string.toString(); | |
765 } | |
766 | |
767 public static AnnotationMirror findAnnotationMirror(ProcessingEnvironment processingEnv, Element element, Class<?> annotationClass) { | |
768 return findAnnotationMirror(processingEnv, element.getAnnotationMirrors(), annotationClass); | |
769 } | |
770 | |
771 public static AnnotationMirror findAnnotationMirror(ProcessingEnvironment processingEnv, List<? extends AnnotationMirror> mirrors, Class<?> annotationClass) { | |
772 TypeElement expectedAnnotationType = processingEnv.getElementUtils().getTypeElement(annotationClass.getCanonicalName()); | |
773 return findAnnotationMirror(mirrors, expectedAnnotationType); | |
774 } | |
775 | |
776 public static AnnotationMirror findAnnotationMirror(List<? extends AnnotationMirror> mirrors, TypeElement expectedAnnotationType) { | |
777 for (AnnotationMirror mirror : mirrors) { | |
778 DeclaredType annotationType = mirror.getAnnotationType(); | |
779 TypeElement actualAnnotationType = (TypeElement) annotationType.asElement(); | |
780 if (actualAnnotationType.equals(expectedAnnotationType)) { | |
781 return mirror; | |
782 } | |
783 } | |
784 return null; | |
785 } | |
786 | |
787 private static PackageElement findPackageElement(Element type) { | |
788 List<Element> hierarchy = getElementHierarchy(type); | |
789 for (Element element : hierarchy) { | |
790 if (element.getKind() == ElementKind.PACKAGE) { | |
791 return (PackageElement) element; | |
792 } | |
793 } | |
794 return null; | |
795 } | |
796 | |
797 public static String firstLetterUpperCase(String name) { | |
798 if (name == null || name.isEmpty()) { | |
799 return name; | |
800 } | |
801 return Character.toUpperCase(name.charAt(0)) + name.substring(1, name.length()); | |
802 } | |
803 | |
804 public static String firstLetterLowerCase(String name) { | |
805 if (name == null || name.isEmpty()) { | |
806 return name; | |
807 } | |
808 return Character.toLowerCase(name.charAt(0)) + name.substring(1, name.length()); | |
809 } | |
810 | |
811 private static ExecutableElement getDeclaredMethod(TypeElement element, String name, TypeMirror[] params) { | |
812 List<ExecutableElement> methods = ElementFilter.methodsIn(element.getEnclosedElements()); | |
813 method: for (ExecutableElement method : methods) { | |
814 if (!method.getSimpleName().toString().equals(name)) { | |
815 continue; | |
816 } | |
817 if (method.getParameters().size() != params.length) { | |
818 continue; | |
819 } | |
820 for (int i = 0; i < params.length; i++) { | |
821 TypeMirror param1 = params[i]; | |
822 TypeMirror param2 = method.getParameters().get(i).asType(); | |
823 if (param1.getKind() != TypeKind.TYPEVAR && param2.getKind() != TypeKind.TYPEVAR) { | |
824 if (!getQualifiedName(param1).equals(getQualifiedName(param2))) { | |
825 continue method; | |
826 } | |
827 } | |
828 } | |
829 return method; | |
830 } | |
831 return null; | |
832 } | |
833 | |
834 private static boolean isDeclaredMethod(TypeElement element, String name, TypeMirror[] params) { | |
835 return getDeclaredMethod(element, name, params) != null; | |
836 } | |
837 | |
838 public static boolean isDeclaredMethodInSuperType(TypeElement element, String name, TypeMirror[] params) { | |
839 List<TypeElement> superElements = getSuperTypes(element); | |
840 | |
841 for (TypeElement typeElement : superElements) { | |
842 if (isDeclaredMethod(typeElement, name, params)) { | |
843 return true; | |
844 } | |
845 } | |
846 return false; | |
847 } | |
848 | |
849 public static boolean typeEquals(TypeMirror type1, TypeMirror type2) { | |
850 if (type1 == null && type2 == null) { | |
851 return true; | |
852 } else if (type1 == null || type2 == null) { | |
853 return false; | |
854 } else if (type1 == type2) { | |
855 return true; | |
856 } | |
857 String qualified1 = getQualifiedName(type1); | |
858 String qualified2 = getQualifiedName(type2); | |
859 | |
860 if (type1.getKind() == TypeKind.ARRAY || type2.getKind() == TypeKind.ARRAY) { | |
861 if (type1.getKind() == TypeKind.ARRAY && type2.getKind() == TypeKind.ARRAY) { | |
862 return typeEquals(((ArrayType) type1).getComponentType(), ((ArrayType) type2).getComponentType()); | |
863 } else { | |
864 return false; | |
865 } | |
866 } | |
867 return qualified1.equals(qualified2); | |
868 } | |
869 | |
870 public static int compareByTypeHierarchy(TypeMirror t1, TypeMirror t2) { | |
871 if (typeEquals(t1, t2)) { | |
872 return 0; | |
873 } | |
874 Set<String> t1SuperSet = new HashSet<>(getQualifiedSuperTypeNames(fromTypeMirror(t1))); | |
875 if (t1SuperSet.contains(getQualifiedName(t2))) { | |
876 return -1; | |
877 } | |
878 | |
879 Set<String> t2SuperSet = new HashSet<>(getQualifiedSuperTypeNames(fromTypeMirror(t2))); | |
880 if (t2SuperSet.contains(getQualifiedName(t1))) { | |
881 return 1; | |
882 } | |
883 return 0; | |
884 } | |
885 | |
886 public static boolean canThrowType(List<? extends TypeMirror> thrownTypes, TypeMirror exceptionType) { | |
887 if (ElementUtils.containsType(thrownTypes, exceptionType)) { | |
888 return true; | |
889 } | |
890 | |
891 if (isRuntimeException(exceptionType)) { | |
892 return true; | |
893 } | |
894 | |
895 // search for any super types | |
896 TypeElement exceptionTypeElement = fromTypeMirror(exceptionType); | |
897 List<TypeElement> superTypes = getSuperTypes(exceptionTypeElement); | |
898 for (TypeElement typeElement : superTypes) { | |
899 if (ElementUtils.containsType(thrownTypes, typeElement.asType())) { | |
900 return true; | |
901 } | |
902 } | |
903 | |
904 return false; | |
905 } | |
906 | |
907 public static Modifier getVisibility(Set<Modifier> modifier) { | |
908 for (Modifier mod : modifier) { | |
909 if (mod == Modifier.PUBLIC || mod == Modifier.PRIVATE || mod == Modifier.PROTECTED) { | |
910 return mod; | |
911 } | |
912 } | |
913 return null; | |
914 } | |
915 | |
916 private static boolean isRuntimeException(TypeMirror type) { | |
917 Set<String> typeSuperSet = new HashSet<>(getQualifiedSuperTypeNames(fromTypeMirror(type))); | |
918 String typeName = getQualifiedName(type); | |
919 if (!typeSuperSet.contains(Throwable.class.getCanonicalName()) && !typeName.equals(Throwable.class.getCanonicalName())) { | |
920 throw new IllegalArgumentException("Given type does not extend Throwable."); | |
921 } | |
922 return typeSuperSet.contains(RuntimeException.class.getCanonicalName()) || typeName.equals(RuntimeException.class.getCanonicalName()); | |
923 } | |
924 | |
925 private static boolean containsType(Collection<? extends TypeMirror> collection, TypeMirror type) { | |
926 for (TypeMirror otherTypeMirror : collection) { | |
927 if (typeEquals(otherTypeMirror, type)) { | |
928 return true; | |
929 } | |
930 } | |
931 return false; | |
932 } | |
933 | |
934 public static boolean isTopLevelClass(TypeMirror importType) { | |
935 TypeElement type = fromTypeMirror(importType); | |
936 if (type != null && type.getEnclosingElement() != null) { | |
937 return !type.getEnclosingElement().getKind().isClass(); | |
938 } | |
939 return true; | |
940 } | |
941 | |
942 public static boolean isObject(TypeMirror actualType) { | |
943 return actualType.getKind() == TypeKind.DECLARED && getQualifiedName(actualType).equals("java.lang.Object"); | |
944 } | |
945 | |
946 } |