1 19 20 package org.netbeans.modules.java.source.usages; 21 22 import com.sun.tools.javac.code.Symbol; 23 import com.sun.tools.javac.util.Convert; 24 import com.sun.tools.javac.util.Name; 25 import java.util.Collection ; 26 import java.util.EnumSet ; 27 import java.util.HashSet ; 28 import java.util.LinkedList ; 29 import java.util.Set ; 30 import javax.lang.model.element.Element; 31 import javax.lang.model.element.ElementKind; 32 import javax.lang.model.element.ExecutableElement; 33 import javax.lang.model.element.TypeElement; 34 import javax.lang.model.element.VariableElement; 35 import javax.lang.model.type.ArrayType; 36 import javax.lang.model.type.DeclaredType; 37 import javax.lang.model.type.ErrorType; 38 import javax.lang.model.type.TypeKind; 39 import javax.lang.model.type.TypeMirror; 40 import javax.lang.model.type.TypeVariable; 41 import org.netbeans.modules.classfile.ByteCodes; 42 import org.netbeans.modules.classfile.CPClassInfo; 43 import org.netbeans.modules.classfile.CPFieldInfo; 44 import org.netbeans.modules.classfile.CPMethodInfo; 45 import org.netbeans.modules.classfile.ClassName; 46 import org.netbeans.modules.classfile.Code; 47 import org.netbeans.modules.classfile.ConstantPool; 48 import org.netbeans.modules.classfile.Method; 49 50 54 public class ClassFileUtil { 55 56 private static final Set <ElementKind> TYPE_DECLS = EnumSet.of(ElementKind.CLASS, ElementKind.INTERFACE, ElementKind.ENUM, ElementKind.ANNOTATION_TYPE); 57 58 59 private ClassFileUtil() { 60 } 61 62 63 public static boolean accessesFiledOrMethod (final String [] fieldInfo, final String [] methodInfo, final Code c, final ConstantPool cp) { 64 BytecodeDecoder bd = new BytecodeDecoder (c.getByteCodes()); 65 for (byte[] iw : bd) { 66 switch (((int)iw[0]&0xff)) { 67 case ByteCodes.bc_putstatic: 68 case ByteCodes.bc_getstatic: 69 case ByteCodes.bc_putfield: 70 case ByteCodes.bc_getfield: 71 if (fieldInfo != null) { 72 int cpIndex = BytecodeDecoder.toInt(iw[1],iw[2]); 73 CPFieldInfo cpFieldInfo = (CPFieldInfo) cp.get(cpIndex); 74 String className = cpFieldInfo.getClassName().getInternalName(); 75 String fieldName = cpFieldInfo.getFieldName(); 76 String signature = cpFieldInfo.getDescriptor(); 77 if (fieldInfo[0].equals(className) && 78 (fieldInfo[1] == null || (fieldInfo[1].equals(fieldName) && fieldInfo[2].equals(signature)))) { 79 return true; 80 } 81 } 82 break; 83 case ByteCodes.bc_invokevirtual: 84 case ByteCodes.bc_invokestatic: 85 case ByteCodes.bc_invokeinterface: 86 case ByteCodes.bc_invokespecial: 87 if (methodInfo != null) { 88 int cpIndex = BytecodeDecoder.toInt(iw[1],iw[2]); 89 CPMethodInfo cpMethodInfo = (CPMethodInfo) cp.get(cpIndex); 90 String className = cpMethodInfo.getClassName().getInternalName(); 91 String methodName = cpMethodInfo.getMethodName(); 92 String signature = cpMethodInfo.getDescriptor(); 93 if (methodInfo[0].equals(className) && 94 (methodInfo[1] == null || (methodInfo[1].equals(methodName) && methodInfo[2].equals(signature)))) { 95 return true; 96 } 97 } 98 break; 99 } 100 } 101 return false; 102 } 103 104 public static boolean accessesFiledOrMethod (final String [] fieldInfo, final String [] methodInfo, final Method m) { 105 Code c = m.getCode(); 106 if (c != null) { 107 ConstantPool cp = m.getClassFile().getConstantPool(); 108 return accessesFiledOrMethod(fieldInfo,methodInfo, c, cp); 109 } 110 else { 111 return false; 112 } 113 } 114 115 public static <T extends Method> Collection <T> accessesFiled (final String [] fieldInfo, final Collection <T> methods) { 116 Collection <T> result = new LinkedList <T> (); 117 for (T m : methods) { 118 if (accessesFiledOrMethod(fieldInfo,null,m)) { 119 result.add(m); 120 } 121 } 122 return result; 123 } 124 125 public static <T extends Method> Collection <T> callsMethod (final String [] methodInfo, final Collection <T> methods) { 126 Collection <T> result = new LinkedList <T> (); 127 for (T m : methods) { 128 if (accessesFiledOrMethod(null,methodInfo,m)) { 129 result.add(m); 130 } 131 } 132 return result; 133 } 134 135 136 public static String [] createFieldDescriptor (final VariableElement ve) { 137 assert ve != null; 138 String [] result = new String [3]; 139 Element enclosingElement = ve.getEnclosingElement(); 140 assert enclosingElement instanceof TypeElement; 141 result[0] = encodeClassNameOrArray ((TypeElement) enclosingElement); 142 result[1] = ve.getSimpleName().toString(); 143 StringBuilder sb = new StringBuilder (); 144 encodeType(ve.asType(),sb); 145 result[2] = sb.toString(); 146 return result; 147 } 148 149 public static String [] createExecutableDescriptor (final ExecutableElement ee) { 150 assert ee != null; 151 final String [] result = new String [3]; 152 final Element enclosingType = ee.getEnclosingElement(); 153 assert enclosingType instanceof TypeElement; 154 result[0] = encodeClassNameOrArray ((TypeElement)enclosingType); 155 final ElementKind kind = ee.getKind(); 156 if (kind == ElementKind.METHOD || kind == ElementKind.CONSTRUCTOR) { 157 final StringBuilder retType = new StringBuilder (); 158 if (kind == ElementKind.METHOD) { 159 result[1] = ee.getSimpleName().toString(); 160 encodeType(ee.getReturnType(), retType); 161 } 162 else { 163 result[1] = "<init>"; retType.append('V'); } 166 StringBuilder sb = new StringBuilder (); 167 sb.append('('); for (VariableElement pd : ee.getParameters()) { 169 encodeType(pd.asType(),sb); 170 } 171 sb.append(')'); sb.append(retType); 173 result[2] = sb.toString(); 174 } 175 else if (kind == ElementKind.INSTANCE_INIT) { 176 result[1] = "<init>"; } 178 else if (kind == ElementKind.STATIC_INIT) { 179 result[1] = "<cinit>"; } 181 else { 182 throw new IllegalArgumentException (); 183 } 184 return result; 185 } 186 187 public static String encodeClassNameOrArray (TypeElement td) { 188 assert td != null; 189 CharSequence qname = td.getQualifiedName(); 190 if (qname != null && "Array".contentEquals(qname) && td.getEnclosingElement().asType().getKind() == TypeKind.NONE) { return "["; } 193 else { 194 return encodeClassName(td); 195 } 196 } 197 198 public static String encodeClassName (TypeElement td) { 199 assert td != null; 200 StringBuilder sb = new StringBuilder (); 201 encodeClassName(td, sb,'.'); return sb.toString(); 203 } 204 205 private static void encodeType (final TypeMirror type, final StringBuilder sb) { 206 switch (type.getKind()) { 207 case VOID: 208 sb.append('V'); break; 210 case BOOLEAN: 211 sb.append('Z'); break; 213 case BYTE: 214 sb.append('B'); break; 216 case SHORT: 217 sb.append('S'); break; 219 case INT: 220 sb.append('I'); break; 222 case LONG: 223 sb.append('J'); break; 225 case CHAR: 226 sb.append('C'); break; 228 case FLOAT: 229 sb.append('F'); break; 231 case DOUBLE: 232 sb.append('D'); break; 234 case ARRAY: 235 sb.append('['); assert type instanceof ArrayType; 237 encodeType(((ArrayType)type).getComponentType(),sb); 238 break; 239 case DECLARED: 240 { 241 sb.append('L'); TypeElement te = (TypeElement) ((DeclaredType)type).asElement(); 243 encodeClassName(te, sb,'/'); 244 sb.append(';'); break; 246 } 247 case TYPEVAR: 248 { 249 assert type instanceof TypeVariable; 250 TypeVariable tr = (TypeVariable) type; 251 TypeMirror upperBound = tr.getUpperBound(); 252 if (upperBound.getKind() == TypeKind.NULL) { 253 sb.append ("Ljava/lang/Object;"); } 255 else { 256 encodeType(upperBound, sb); 257 } 258 break; 259 } 260 case ERROR: 261 { 262 TypeElement te = (TypeElement) ((ErrorType)type).asElement(); 263 if (te != null) { 264 sb.append('L'); 265 encodeClassName(te, sb,'/'); 266 sb.append(';'); break; 268 } 269 } 270 default: 271 throw new IllegalArgumentException (); 272 } 273 } 274 275 static char[] nameChars = new char[512]; 277 278 public static void encodeClassName (TypeElement te, final StringBuilder sb, final char separator) { 279 Name name = ((Symbol.ClassSymbol)te).flatname; 280 assert name != null; 281 int nameLength = name.len; 282 if (nameChars.length < nameLength) { 283 nameChars = new char[nameLength]; 284 } 285 Convert.utf2chars(name.table.names, name.index, nameChars, 0, nameLength); 286 if (separator != '.') { for (int i=0; i<nameLength; i++) { 288 if (nameChars[i] == '.') { nameChars[i] = separator; 290 } 291 } 292 } 293 sb.append(nameChars,0,nameLength); 294 } 295 296 300 public static ClassName getType (final String jvmTypeId) { 301 if (jvmTypeId.length()<2) { 303 return null; } 305 else if (jvmTypeId.charAt(0) == 'L') { 306 return ClassName.getClassName(jvmTypeId); 308 } 309 else if (jvmTypeId.charAt(0) == '[') { 310 return getType (jvmTypeId.substring(1)); 312 } 313 return null; 315 } 316 317 public static ClassName getType (final CPClassInfo ci) { 318 String type = ci.getName(); 319 if (type.charAt(0)=='[') { return getType(type); 321 } 322 else { 323 return ci.getClassName(); 324 } 325 } 326 327 public static ClassName[] getTypesFromMethodTypeSignature (final String jvmTypeId) { 328 Set <ClassName> result = new HashSet <ClassName> (); 329 methodTypeSignature (jvmTypeId, new int[] {0}, result); 330 return result.toArray(new ClassName[result.size()]); 331 } 332 333 public static ClassName[] getTypesFromFiledTypeSignature (final String jvmTypeId) { 334 Set <ClassName> result = new HashSet <ClassName> (); 335 typeSignatureType (jvmTypeId, new int[] {0}, result, false); 336 return result.toArray(new ClassName[result.size()]); 337 } 338 339 public static ClassName[] getTypesFromClassTypeSignature (final String jvmTypeId) { 340 Set <ClassName> result = new HashSet <ClassName> (); 341 classTypeSignature (jvmTypeId, new int[] {0}, result); 342 return result.toArray(new ClassName[result.size()]); 343 } 344 345 private static char getChar (final String buffer, final int pos) { 346 if (pos>=buffer.length()) { 347 throw new IllegalStateException (); 348 } 349 return buffer.charAt(pos); 350 } 351 352 private static void classTypeSignature (final String jvmTypeId, final int[] pos, final Set <ClassName> s) { 353 char c = getChar (jvmTypeId, pos[0]); 354 if (c == '<') { 355 formalTypeParameters (jvmTypeId, pos, s); 356 c = getChar (jvmTypeId, pos[0]); 357 } 358 typeSignatureType (jvmTypeId, pos, s, false); 359 while (pos[0]<jvmTypeId.length()) { 360 typeSignatureType (jvmTypeId, pos, s, false); 361 } 362 } 363 364 private static void methodTypeSignature (final String jvmTypeId, final int[] pos, final Set <ClassName> s) { 365 char c = getChar (jvmTypeId, pos[0]); 366 if (c == '<') { 367 formalTypeParameters (jvmTypeId, pos, s); 368 c = getChar (jvmTypeId, pos[0]); 369 } 370 if (c!='(') { 371 throw new IllegalStateException (jvmTypeId); 372 } 373 pos[0]++; 374 c = getChar (jvmTypeId, pos[0]); 375 while (c != ')') { 376 typeSignatureType (jvmTypeId, pos, s, false); 377 c = getChar (jvmTypeId, pos[0]); 378 } 379 pos[0]++; 380 typeSignatureType (jvmTypeId, pos, s, false); } 383 384 385 private static void formalTypeParam (final String jvmTypeId, final int[] pos, final Set <ClassName> s) { 386 char c; 388 do { 389 c = getChar(jvmTypeId, pos[0]++); 390 } while (c!=':'); 391 c = getChar(jvmTypeId, pos[0]); 392 if (c !=':') { 393 typeSignatureType(jvmTypeId, pos, s, true); 394 c = getChar (jvmTypeId, pos[0]); 395 } 396 while (c == ':') { 397 pos[0]++; 398 typeSignatureType(jvmTypeId, pos, s, true); 399 c = getChar (jvmTypeId, pos[0]); 400 } 401 } 402 403 404 405 private static void formalTypeParameters (final String jvmTypeId, final int[] pos, final Set <ClassName> s) { 406 char c = getChar(jvmTypeId, pos[0]++); 407 if (c != '<') { 408 throw new IllegalArgumentException (jvmTypeId); 409 } 410 c = getChar (jvmTypeId, pos[0]); 411 while (c !='>') { 412 formalTypeParam (jvmTypeId, pos, s); 413 c = getChar (jvmTypeId, pos[0]); 414 } 415 pos[0]++; 416 } 417 418 private static void typeArgument (final String jvmTypeId, final int[] pos, final Set <ClassName> s) { 419 char c = getChar (jvmTypeId, pos[0]); 420 if (c == '*') { 421 pos[0]++; 422 return; 423 } 424 else if (c == '+' || c == '-') { 425 pos[0]++; 426 typeSignatureType (jvmTypeId, pos, s, true); 427 } 428 else { 429 typeSignatureType (jvmTypeId, pos, s, true); 430 } 431 } 432 433 434 private static void typeArgumentsList (final String jvmTypeId, final int[] pos, final Set <ClassName> s) { 435 char c = getChar (jvmTypeId, pos[0]++); 436 if (c != '<') { 437 throw new IllegalStateException (jvmTypeId); 438 } 439 c = getChar (jvmTypeId, pos[0]); 440 while (c !='>') { 441 typeArgument (jvmTypeId, pos, s); 442 c = getChar (jvmTypeId, pos[0]); 443 } 444 pos[0]++; 445 } 446 447 private static void typeSignatureType (final String jvmTypeId, final int[] pos, final Set <ClassName> s, boolean add) { 448 char c = getChar(jvmTypeId, pos[0]++); 449 switch (c) { 450 case 'B': 451 case 'C': 452 case 'D': 453 case 'F': 454 case 'I': 455 case 'J': 456 case 'S': 457 case 'V': 458 case 'Z': 459 break; 461 case 'L': 462 StringBuilder builder = new StringBuilder (); 463 do { 464 builder.append (c); 465 c = getChar(jvmTypeId, pos[0]); 466 if (c=='<') { 467 typeArgumentsList (jvmTypeId,pos, s); 468 c = getChar(jvmTypeId, pos[0]++); } 470 else { 471 pos[0]++; 472 } 473 } while (c != ';'); 474 builder.append (c); 475 if (add) { 476 s.add(ClassName.getClassName(builder.toString())); 477 } 478 break; 479 case 'T': 480 do { 481 c = getChar(jvmTypeId, pos[0]++); 482 } while (c != ';'); 483 break; 484 case '[': 485 typeSignatureType (jvmTypeId, pos, s, add); 486 break; 487 } 488 } 489 490 } 491 | Popular Tags |