aboutsummaryrefslogtreecommitdiff
path: root/src/main/java/ftbsc/lll/processor/tools/ASTUtils.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/ftbsc/lll/processor/tools/ASTUtils.java')
-rw-r--r--src/main/java/ftbsc/lll/processor/tools/ASTUtils.java151
1 files changed, 151 insertions, 0 deletions
diff --git a/src/main/java/ftbsc/lll/processor/tools/ASTUtils.java b/src/main/java/ftbsc/lll/processor/tools/ASTUtils.java
new file mode 100644
index 0000000..c35e008
--- /dev/null
+++ b/src/main/java/ftbsc/lll/processor/tools/ASTUtils.java
@@ -0,0 +1,151 @@
+package ftbsc.lll.processor.tools;
+
+import com.squareup.javapoet.ArrayTypeName;
+import com.squareup.javapoet.ClassName;
+import com.squareup.javapoet.MethodSpec;
+import com.squareup.javapoet.TypeName;
+import ftbsc.lll.tools.DescriptorBuilder;
+
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.element.Modifier;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.type.MirroredTypeException;
+import javax.lang.model.type.TypeMirror;
+import java.lang.annotation.Annotation;
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * Collection of static utils that didn't really fit into the main class.
+ */
+public class ASTUtils {
+ /**
+ * Finds, among the methods of a class cl, the one annotated with ann, and tries to build
+ * a {@link ExecutableElement} from it.
+ * @param cl the {@link ExecutableElement} for the class containing the desired method
+ * @param ann the {@link Class} corresponding to the desired annotation
+ * @return a {@link List} of {@link MethodSpec}s annotated with the given annotation
+ * @since 0.2.0
+ */
+ public static List<ExecutableElement> findAnnotatedMethods(TypeElement cl, Class<? extends Annotation> ann) {
+ return cl.getEnclosedElements()
+ .stream()
+ .filter(e -> e.getAnnotation(ann) != null)
+ .map(e -> (ExecutableElement) e)
+ .collect(Collectors.toList());
+ }
+
+ /**
+ * Builds a type descriptor from the given {@link TypeName}.
+ * @param type the {@link TypeName} representing the desired type
+ * @return a {@link String} containing the relevant descriptor
+ */
+ public static String descriptorFromType(TypeName type) {
+ StringBuilder desc = new StringBuilder();
+ //add array brackets
+ while(type instanceof ArrayTypeName) {
+ desc.append("[");
+ type = ((ArrayTypeName) type).componentType;
+ }
+ if(type instanceof ClassName) {
+ ClassName var = (ClassName) type;
+ desc.append(DescriptorBuilder.nameToDescriptor(var.canonicalName(), 0));
+ } else {
+ if(TypeName.BOOLEAN.equals(type))
+ desc.append("Z");
+ else if(TypeName.CHAR.equals(type))
+ desc.append("C");
+ else if(TypeName.BYTE.equals(type))
+ desc.append("B");
+ else if(TypeName.SHORT.equals(type))
+ desc.append("S");
+ else if(TypeName.INT.equals(type))
+ desc.append("I");
+ else if(TypeName.FLOAT.equals(type))
+ desc.append("F");
+ else if(TypeName.LONG.equals(type))
+ desc.append("J");
+ else if(TypeName.DOUBLE.equals(type))
+ desc.append("D");
+ else if(TypeName.VOID.equals(type))
+ desc.append("V");
+ }
+ return desc.toString();
+ }
+
+ /**
+ * Builds a type descriptor from the given {@link TypeMirror}.
+ * @param t the {@link TypeMirror} representing the desired type
+ * @return a {@link String} containing the relevant descriptor
+ */
+ public static String descriptorFromType(TypeMirror t) {
+ return descriptorFromType(TypeName.get(t));
+ }
+
+ /**
+ * Builds a method descriptor from the given {@link ExecutableElement}.
+ * @param m the {@link ExecutableElement} for the method
+ * @return a {@link String} containing the relevant descriptor
+ */
+ public static String descriptorFromExecutableElement(ExecutableElement m) {
+ StringBuilder methodSignature = new StringBuilder();
+ methodSignature.append("(");
+ m.getParameters().forEach(p -> methodSignature.append(descriptorFromType(p.asType())));
+ methodSignature.append(")");
+ methodSignature.append(descriptorFromType(m.getReturnType()));
+ return methodSignature.toString();
+ }
+
+ /**
+ * Maps a {@link javax.lang.model.element.Modifier} to its reflective
+ * {@link java.lang.reflect.Modifier} equivalent.
+ * @param m the {@link Modifier} to map
+ * @return an integer representing the modifier
+ * @see java.lang.reflect.Modifier
+ * @since 0.2.0
+ */
+ public static int mapModifier(Modifier m) {
+ switch(m) {
+ case PUBLIC:
+ return java.lang.reflect.Modifier.PUBLIC;
+ case PROTECTED:
+ return java.lang.reflect.Modifier.PROTECTED;
+ case PRIVATE:
+ return java.lang.reflect.Modifier.PRIVATE;
+ case ABSTRACT:
+ return java.lang.reflect.Modifier.ABSTRACT;
+ case STATIC:
+ return java.lang.reflect.Modifier.STATIC;
+ case FINAL:
+ return java.lang.reflect.Modifier.FINAL;
+ case TRANSIENT:
+ return java.lang.reflect.Modifier.TRANSIENT;
+ case VOLATILE:
+ return java.lang.reflect.Modifier.VOLATILE;
+ case SYNCHRONIZED:
+ return java.lang.reflect.Modifier.SYNCHRONIZED;
+ case NATIVE:
+ return java.lang.reflect.Modifier.NATIVE;
+ case STRICTFP:
+ return java.lang.reflect.Modifier.STRICT;
+ default:
+ return 0;
+ }
+ }
+
+ /**
+ * Safely converts a {@link Class} to its fully qualified name. See
+ * <a href="https://area-51.blog/2009/02/13/getting-class-values-from-annotations-in-an-annotationprocessor">this blogpost</a>
+ * for more information.
+ * @param clazz the class to get the name for
+ * @return the fully qualified name of the given class
+ * @since 0.3.0
+ */
+ public static String getClassFullyQualifiedName(Class<?> clazz) {
+ try {
+ return clazz.getCanonicalName();
+ } catch(MirroredTypeException e) {
+ return e.getTypeMirror().toString();
+ }
+ }
+}