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 }