Home | History | Annotate | Download | only in util
      1 package annotations.util;
      2 
      3 import com.sun.source.tree.ArrayTypeTree;
      4 import com.sun.source.tree.MethodTree;
      5 import com.sun.source.tree.Tree;
      6 import com.sun.tools.javac.code.Type;
      7 import com.sun.tools.javac.code.TypeTag;
      8 import com.sun.tools.javac.tree.JCTree.JCExpression;
      9 import com.sun.tools.javac.tree.JCTree.JCMethodDecl;
     10 import com.sun.tools.javac.tree.JCTree.JCVariableDecl;
     11 import com.sun.tools.javac.util.List;
     12 
     13 import plume.UtilMDE;
     14 
     15 import javax.lang.model.element.ExecutableElement;
     16 import javax.lang.model.element.VariableElement;
     17 import javax.lang.model.type.ArrayType;
     18 import javax.lang.model.type.TypeKind;
     19 import javax.lang.model.type.TypeMirror;
     20 
     21 /**
     22  * Class to generate class formatted names from Trees.
     23  *
     24  * @author mcarthur
     25  */
     26 public class JVMNames {
     27 
     28     /**
     29      * Converts a MethodTree into a jvml format method signature.
     30      * There is probably an API to do this, but I couldn't find it.
     31      *
     32      * @param methodTree the tree to convert
     33      * @return a String signature of methodTree in jvml format
     34      */
     35     public static String getJVMMethodName(MethodTree methodTree) {
     36         ExecutableElement methodElement = ((JCMethodDecl) methodTree).sym;
     37         StringBuilder builder = new StringBuilder();
     38         String returnTypeStr;
     39         builder.append(methodTree.getName());
     40         builder.append("(");
     41 
     42         if (methodElement == null) {
     43             // use source AST in lieu of symbol table
     44             List<JCVariableDecl> params = ((JCMethodDecl) methodTree).params;
     45             JCVariableDecl param = params.head;
     46             JCExpression typeTree = ((JCMethodDecl) methodTree).restype;
     47             returnTypeStr = treeToJVMLString(typeTree);
     48             while (param != null) {
     49                 builder.append(treeToJVMLString(param.vartype));
     50                 params = params.tail;
     51                 param = params.head;
     52             }
     53         } else {
     54             TypeMirror returnType = methodElement.getReturnType();
     55             returnTypeStr = typeToJvmlString((Type)returnType);
     56             for (VariableElement ve : methodElement.getParameters()) {
     57                 Type vt = (Type) ve.asType();
     58                 if (vt.getTag() == TypeTag.TYPEVAR) {
     59                     vt = vt.getUpperBound();
     60                 }
     61                 builder.append(typeToJvmlString(vt));
     62             }
     63         }
     64         builder.append(")");
     65         builder.append(returnTypeStr);
     66         return builder.toString();
     67     }
     68 
     69     /**
     70      * Converts a method element into a jvml format method signature.
     71      * There is probably an API to do this, but I couldn't find it.
     72      *
     73      * @param methodElement the method element to convert
     74      * @return a String signature of methodElement in jvml format
     75      */
     76     public static String getJVMMethodName(ExecutableElement methodElement) {
     77         StringBuilder builder = new StringBuilder();
     78         String returnTypeStr;
     79         builder.append(methodElement.getSimpleName());
     80         builder.append("(");
     81         TypeMirror returnType = methodElement.getReturnType();
     82         returnTypeStr = typeToJvmlString((Type)returnType);
     83         for (VariableElement ve : methodElement.getParameters()) {
     84             Type vt = (Type) ve.asType();
     85             if (vt.getTag() == TypeTag.TYPEVAR) {
     86                 vt = vt.getUpperBound();
     87             }
     88             builder.append(typeToJvmlString(vt));
     89         }
     90         builder.append(")");
     91         builder.append(returnTypeStr);
     92         return builder.toString();
     93     }
     94 
     95     /**
     96      * Create a JVML string for a type.
     97      * Uses {@link UtilMDE#binaryNameToFieldDescriptor(String)}
     98      *
     99      * Array strings are built by recursively converting the component type.
    100      *
    101      * @param type the Type to convert to JVML
    102      * @return the JVML representation of type
    103      */
    104     public static String typeToJvmlString(Type type) {
    105         if (type.getKind() == TypeKind.ARRAY) {
    106             return "[" + typeToJvmlString((Type) ((ArrayType) type).getComponentType());
    107         } else if (type.getKind() == TypeKind.INTERSECTION) {
    108             // replace w/erasure (== erasure of 1st conjunct)
    109             return typeToJvmlString(type.tsym.erasure_field);
    110         } else if (type.getKind() == TypeKind.VOID) {
    111             return "V";  // special case since UtilMDE doesn't handle void
    112         } else {
    113             return UtilMDE.binaryNameToFieldDescriptor(type.tsym.flatName().toString());
    114         }
    115     }
    116 
    117     /**
    118      * Create a JVML string for an AST node representing a type.
    119      *
    120      * @param typeTree a Tree representing a type
    121      * @return the JVML representation of type
    122      */
    123     private static String treeToJVMLString(Tree typeTree) {
    124         StringBuilder builder = new StringBuilder();
    125         treeToJVMLString(typeTree, builder);
    126         return builder.toString();
    127     }
    128 
    129     private static void treeToJVMLString(Tree typeTree, StringBuilder builder) {
    130         // FIXME: not robust in presence of comments
    131         switch (typeTree.getKind()) {
    132         case ARRAY_TYPE:
    133             builder.append('[');
    134             treeToJVMLString(((ArrayTypeTree) typeTree).getType(), builder);
    135             break;
    136         default:
    137             String str = typeTree.toString();
    138             builder.append("void".equals(str) ? "V"
    139                 : UtilMDE.binaryNameToFieldDescriptor(typeTree.toString()));
    140             break;
    141         }
    142     }
    143 
    144     public static String jvmlStringToJavaTypeString(String str) {
    145         return str.equals("V") ? "void"
    146                 : UtilMDE.fieldDescriptorToBinaryName(str);
    147     }
    148 }
    149