aboutsummaryrefslogtreecommitdiff
path: root/src/main/java/ftbsc/lll/processor/tools/JavaPoetUtils.java
blob: 51f058bd933be2770197ccf34d92d642fb7f2fe7 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
package ftbsc.lll.processor.tools;

import com.squareup.javapoet.*;
import ftbsc.lll.tools.DescriptorBuilder;
import ftbsc.lll.proxies.MethodProxy;
import ftbsc.lll.proxies.FieldProxy;

import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.Modifier;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.util.Elements;
import java.lang.annotation.Annotation;
import java.util.List;
import java.util.function.Function;

import static ftbsc.lll.processor.tools.ASTUtils.classArrayFromAnnotation;

/**
 * Collection of static utils that rely on JavaPoet to function.
 */
public class JavaPoetUtils {
   /**
    * Builds a {@link MethodSpec} for a public method whose body simply returns a {@link String}.
    * @param name the name of the method
    * @param returnString the {@link String} to return
    * @return the built {@link MethodSpec}
    */
   public static MethodSpec buildStringReturnMethod(String name, String returnString) {
      return MethodSpec.methodBuilder(name)
         .addModifiers(Modifier.PUBLIC)
         .addAnnotation(Override.class)
         .returns(String.class)
         .addStatement("return $S", returnString)
         .build();
   }

   /**
    * 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 || type instanceof ParameterizedTypeName) {
         ClassName var = type instanceof ParameterizedTypeName ? ((ParameterizedTypeName) type).rawType : (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();
   }

   /**
    * Builds a (partial, not including the return type) method descriptor from its parameters
    * @param ann the annotation containing the class
    * @param fun the annotation function returning the class
    * @param elementUtils the {@link Elements} containing utils for the current processing environment
    * @param <T> the type of the annotation carrying the information
    * @return the method descriptor
    */
   public static <T extends Annotation> String methodDescriptorFromParams(T ann, Function<T, Class<?>[]> fun, Elements elementUtils) {
      List<TypeMirror> mirrors = classArrayFromAnnotation(ann, fun, elementUtils);
      StringBuilder sb = new StringBuilder("(");
      for(TypeMirror t : mirrors)
         sb.append(descriptorFromType(t));
      sb.append(")");
      return sb.toString();
   }

   /**
    * Adds to the given {@link MethodSpec.Builder} the given line of code,
    * containing a call to a method of a {@link MethodProxy.Builder} or a
    * {@link FieldProxy.Builder}.
    * @param b the {@link MethodSpec.Builder}
    * @param proxyBuilderName the name of the proxy builder
    * @param proxyBuilderMethod the method to call
    * @param t the {@link TypeMirror} to add
    * @since 0.4.0
    */
   public static void addTypeToProxyGenerator(MethodSpec.Builder b, String proxyBuilderName, String proxyBuilderMethod, TypeMirror t) {
      String insn = String.format("%s.%s", proxyBuilderName, proxyBuilderMethod);
      if(t.getKind().isPrimitive())
         b.addStatement(insn + "($T.class)", t);
      else {
         ArrayContainer arr = new ArrayContainer(t);
         b.addStatement(
            insn + "($S, $L)",
            arr.innermostComponent,
            arr.arrayLevel
         );
      }
   }
}