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 */ getJVMMethodName(MethodTree methodTree)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 */ getJVMMethodName(ExecutableElement methodElement)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 */ typeToJvmlString(Type type)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 */ treeToJVMLString(Tree typeTree)123 private static String treeToJVMLString(Tree typeTree) { 124 StringBuilder builder = new StringBuilder(); 125 treeToJVMLString(typeTree, builder); 126 return builder.toString(); 127 } 128 treeToJVMLString(Tree typeTree, StringBuilder builder)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 jvmlStringToJavaTypeString(String str)144 public static String jvmlStringToJavaTypeString(String str) { 145 return str.equals("V") ? "void" 146 : UtilMDE.fieldDescriptorToBinaryName(str); 147 } 148 } 149