1 19 package org.netbeans.modules.java.source.usages; 20 21 import com.sun.tools.javac.code.Flags; 22 import com.sun.tools.javac.code.Symbol; 23 import com.sun.tools.javac.code.Type; 24 import com.sun.tools.javac.code.Types; 25 import java.io.PrintWriter ; 26 import java.util.List ; 27 import java.util.Map.Entry; 28 import java.util.logging.Logger ; 29 import javax.lang.model.element.AnnotationMirror; 30 import javax.lang.model.element.AnnotationValue; 31 import javax.lang.model.element.Element; 32 import javax.lang.model.element.ElementKind; 33 import javax.lang.model.element.ExecutableElement; 34 import javax.lang.model.element.Modifier; 35 import javax.lang.model.element.TypeElement; 36 import javax.lang.model.element.TypeParameterElement; 37 import javax.lang.model.element.VariableElement; 38 import javax.lang.model.type.ArrayType; 39 import javax.lang.model.type.DeclaredType; 40 import javax.lang.model.type.ErrorType; 41 import javax.lang.model.type.ExecutableType; 42 import javax.lang.model.type.NoType; 43 import javax.lang.model.type.NullType; 44 import javax.lang.model.type.PrimitiveType; 45 import javax.lang.model.type.TypeKind; 46 import javax.lang.model.type.TypeMirror; 47 import javax.lang.model.type.TypeVariable; 48 import javax.lang.model.type.WildcardType; 49 import javax.lang.model.util.ElementFilter; 50 import javax.lang.model.util.SimpleAnnotationValueVisitor6; 51 import javax.lang.model.util.SimpleTypeVisitor6; 52 53 75 public class SymbolDumper extends SimpleTypeVisitor6<Void , Boolean > { 76 77 private PrintWriter output; 78 private Types types; 79 80 81 public SymbolDumper(PrintWriter output, Types types) { 82 this.output = output; 83 this.types = types; 84 } 85 86 public Void visitPrimitive(PrimitiveType t, Boolean p) { 87 switch (t.getKind()) { 88 case BOOLEAN: 89 output.append('Z'); break; 91 case BYTE: 92 output.append('B'); break; 94 case SHORT: 95 output.append('S'); break; 97 case INT: 98 output.append('I'); break; 100 case LONG: 101 output.append('J'); break; 103 case CHAR: 104 output.append('C'); break; 106 case FLOAT: 107 output.append('F'); break; 109 case DOUBLE: 110 output.append('D'); break; 112 default: 113 throw new IllegalArgumentException ("Should not happend. Or can it?"); 114 } 115 return null; 116 } 117 118 public Void visitNoType(NoType t, Boolean p) { 119 switch (t.getKind()) { 120 case VOID: 121 output.append('V'); 122 break; 123 case PACKAGE: 124 new Exception ("what should be printed here?").printStackTrace(); 125 break; 126 } 127 return null; 128 } 129 130 public Void visitNull(NullType t, Boolean p) { 131 new Exception ("what should be printed here?").printStackTrace(); 132 return null; 133 } 134 135 public Void visitArray(ArrayType t, Boolean p) { 136 output.append('['); visit(t.getComponentType()); 138 return null; 139 } 140 141 public Void visitDeclared(DeclaredType t, Boolean p) { 142 output.append('L'); 143 output.append(ClassFileUtil.encodeClassName((TypeElement) t.asElement())); 144 List <? extends TypeMirror> actualTypeParameters = t.getTypeArguments(); 145 146 if (!actualTypeParameters.isEmpty()) { 147 output.append('<'); 148 for (TypeMirror param : actualTypeParameters) { 149 visit(param); 150 } 151 output.append('>'); 152 } 153 output.append(';'); 154 return null; 155 } 156 157 public Void visitError(ErrorType t, Boolean p) { 158 TypeElement te = (TypeElement) t.asElement(); 159 160 output.append('R'); 161 162 if (te != null) { 163 output.append(te.getSimpleName().toString()); 164 } 165 166 output.append(';'); 167 168 return null; 169 } 170 171 public Void visitTypeVariable(TypeVariable t, Boolean p) { 172 if (p == Boolean.TRUE) { 173 output.append(t.asElement().getSimpleName().toString()); 174 output.append(':'); 175 assert t.getLowerBound().getKind() == TypeKind.NULL : "currently not handled!" ; 176 Type boundImpl = ((Type) t.getUpperBound()); 177 178 if (boundImpl.isCompound()) { 179 if (boundImpl.getKind() == TypeKind.EXECUTABLE || boundImpl.getKind() == TypeKind.PACKAGE) 180 throw new IllegalArgumentException (boundImpl.toString()); 181 Type sup = types.supertype(boundImpl); 182 visit((sup == Type.noType || sup == boundImpl || sup == null) 183 ? types.interfaces(boundImpl) 184 : types.interfaces(boundImpl).prepend(sup)); 185 } else { 186 visit(t.getUpperBound()); 187 } 188 189 output.append(';'); 190 } else { 191 output.append('Q'); 192 output.append(t.asElement().getSimpleName().toString()); 193 output.append(';'); 194 } 195 196 return null; 197 } 198 199 public Void visitWildcard(WildcardType t, Boolean p) { 200 boolean wasSomething = false; 201 202 if (t.getExtendsBound() != null) { 203 output.append("+"); 204 visit(t.getExtendsBound()); 205 wasSomething = true; 206 } 207 if (t.getSuperBound() != null) { 208 output.append("-"); 209 visit(t.getSuperBound()); 210 wasSomething = true; 211 } 212 213 if (!wasSomething) { 214 output.append('?'); 215 } 216 return null; 217 } 218 219 public Void visitExecutable(ExecutableType t, Boolean p) { 220 throw new IllegalStateException ("This cannot be handled correctly, and should hopefully never happen..."); 221 } 222 223 public Void visitUnknown(TypeMirror t, Boolean p) { 224 new Exception ("what should be printed here?").printStackTrace(); 225 return null; 226 } 227 228 public void visit(List <? extends TypeMirror> l) { 229 for (TypeMirror t : l) { 230 visit(t); 231 } 232 } 233 234 public void visit(List <? extends TypeMirror> l, Boolean p) { 235 for (TypeMirror t : l) { 236 visit(t, p); 237 } 238 } 239 240 public static void dump(PrintWriter output, Types types, TypeElement type, Element enclosingElement) { 241 SymbolDumper.dumpImpl(output, types, type, enclosingElement); 242 243 output.append('\n'); 244 245 for (Element e : type.getEnclosedElements()) { 246 if (e.getKind().isClass() || e.getKind().isInterface()) { 247 continue; 249 } 250 SymbolDumper.dumpImpl(output, types, e); 251 } 252 253 output.append('W'); 254 255 dumpAnnotations(new SymbolDumper(output, types), type); 256 } 257 258 private static void dumpImpl(PrintWriter output, Types types, TypeElement type, Element enclosingElement) { 259 SymbolDumper d = new SymbolDumper(output, types); 260 261 output.append('G'); 262 dumpFlags(output, ((Symbol) type).flags_field & ~ (Flags.FROMCLASS|Flags.UNATTRIBUTED)); 263 List <? extends TypeParameterElement> params = type.getTypeParameters(); 264 265 if (!params.isEmpty()) { 266 output.append('<'); 267 for (TypeParameterElement e : params) { 268 d.visit(e.asType(), Boolean.TRUE); 269 } 270 output.append('>'); 271 } 272 dumpName(output, ClassFileUtil.encodeClassName(type)); 273 dumpEnclosingElement(d, enclosingElement); 274 275 TypeMirror tm = type.getSuperclass(); 276 277 if (tm.getKind() != TypeKind.NONE) { 278 d.visit(tm); 279 } else { 280 if (!"java.lang.Object".equals(type.getQualifiedName().toString())) { 282 output.append("Ljava.lang.Object;"); 283 } else { 284 output.append(";"); 285 } 286 } 287 288 d.visit(type.getInterfaces()); 289 output.append(';'); 290 291 dumpInnerclasses(output, ElementFilter.typesIn(type.getEnclosedElements())); 292 } 293 294 private static void dumpEnclosingElement(SymbolDumper dumper, Element enclosingElement) { 295 if (enclosingElement != null) { 296 if (enclosingElement.getKind().isClass() || enclosingElement.getKind().isInterface()) { 297 dumpName(dumper.output, ClassFileUtil.encodeClassName((TypeElement)enclosingElement)); 298 } else { 299 dumpName(dumper.output, ClassFileUtil.encodeClassName((TypeElement)enclosingElement.getEnclosingElement())); 300 ExecutableElement enclosingMethod = (ExecutableElement)enclosingElement; 301 dumpName(dumper.output, enclosingMethod.getSimpleName()); 302 ExecutableType enclosingMethodType = (ExecutableType)((Symbol)enclosingMethod).externalType(dumper.types); 303 dumper.output.append('('); 304 dumper.visit(enclosingMethodType.getParameterTypes()); 305 dumper.output.append(')'); 306 dumper.output.append('('); 307 dumper.visit(enclosingMethodType.getThrownTypes()); 308 dumper.output.append(')'); 309 dumper.visit(enclosingMethodType.getReturnType()); 310 } 311 } 312 dumper.output.append(';'); 313 } 314 315 private static void dumpInnerclasses(PrintWriter output, List <TypeElement> innerClasses) { 316 for (TypeElement innerClass : innerClasses) { 317 dumpName(output, innerClass.getSimpleName()); 318 } 319 output.append(';'); 320 } 321 322 private static void dumpImpl(PrintWriter output, Types types, Element el) { 323 if (el.getKind().isField()) { 324 dumpImpl(output, types, (VariableElement) el); 325 output.append('\n'); 326 return; 327 } 328 if (el.getKind() == ElementKind.METHOD || el.getKind() == ElementKind.CONSTRUCTOR) { 329 dumpImpl(output, types, (ExecutableElement) el); 330 output.append('\n'); 331 return; 332 } 333 334 Logger.getLogger(SymbolDumper.class.getName()).info("Unhandled ElementKind: " + el.getKind()); 335 } 336 337 private static void dumpImpl(PrintWriter output, Types types, VariableElement variable) { 338 SymbolDumper d = new SymbolDumper(output, types); 339 340 output.append('A'); 341 dumpFlags(output, ((Symbol) variable).flags_field); 342 d.visit(variable.asType()); 343 dumpName(output, variable.getSimpleName()); 344 345 if (variable.getModifiers().contains(Modifier.STATIC) && variable.getConstantValue() != null) { 346 switch (variable.asType().getKind()) { 347 case BOOLEAN: 348 output.append('Z'); output.append(String.valueOf(variable.getConstantValue())); 350 break; 351 case BYTE: 352 output.append('B'); output.append(String.valueOf(variable.getConstantValue())); 354 break; 355 case SHORT: 356 output.append('S'); output.append(String.valueOf(variable.getConstantValue())); 358 break; 359 case INT: 360 output.append('I'); output.append(String.valueOf(variable.getConstantValue())); 362 break; 363 case LONG: 364 output.append('J'); output.append(String.valueOf(variable.getConstantValue())); 366 break; 367 case CHAR: 368 output.append('C'); appendEscapedString(output, String.valueOf(variable.getConstantValue())); 370 break; 371 case FLOAT: 372 output.append('F'); output.append(String.valueOf(variable.getConstantValue())); 374 break; 375 case DOUBLE: 376 output.append('D'); output.append(String.valueOf(variable.getConstantValue())); 378 break; 379 case DECLARED: 380 output.append('L'); 381 TypeMirror varType = variable.asType(); 382 if (varType.getKind() == TypeKind.DECLARED && "java.lang.String".equals(((TypeElement)((DeclaredType)varType).asElement()).getQualifiedName().toString())) { 383 appendEscapedString(output, String.valueOf(variable.getConstantValue())); 384 } 385 break; 386 default: 387 output.append("X"); 388 } 389 } else { 390 output.append("X"); 391 } 392 393 output.append(";"); 394 395 dumpAnnotations(d, variable); 396 } 397 398 private static void dumpImpl(PrintWriter output, Types types, ExecutableElement executable) { 399 SymbolDumper d = new SymbolDumper(output, types); 400 ExecutableType type = (ExecutableType) executable.asType(); 401 402 output.append('E'); 403 dumpFlags(output, ((Symbol) executable).flags_field); 404 dumpTypeVariables(d, type.getTypeVariables()); 405 dumpName(output, executable.getSimpleName()); 406 output.append('('); 407 List <? extends TypeMirror> paramTypes = type.getParameterTypes(); 408 List <? extends VariableElement> paramElems = executable.getParameters(); 409 410 assert paramElems.size() == paramTypes.size(); 411 412 for (int cntr = 0; cntr < paramTypes.size(); cntr++) { 413 dumpFlags(output, ((Symbol) paramElems.get(cntr)).flags_field); 414 d.visit(paramTypes.get(cntr), Boolean.FALSE); 415 dumpName(output, paramElems.get(cntr).getSimpleName()); 416 } 417 output.append(')'); 418 419 output.append('('); 420 421 for (TypeMirror t : executable.getThrownTypes()) { 422 d.visit(t); 423 } 424 425 output.append(')'); 426 427 d.visit(type.getReturnType()); 428 429 dumpAnnotations(d, executable); 430 431 AnnotationValue value = executable.getDefaultValue(); 433 434 if (value != null) { 435 new AnnotationValueVisitorImpl().visit(value, d); 436 } else { 437 output.append(';'); 438 } 439 } 440 441 private static void appendEscapedString(PrintWriter output, String value) { 442 value = value.replaceAll("\\\\", "\\\\\\\\"); 443 value = value.replaceAll("@", "\\\\a"); 444 value = value.replaceAll(";", "\\\\b"); 445 446 StringBuffer result = new StringBuffer (); 447 448 for (int cntr = 0; cntr < value.length(); cntr++) { 449 char c = value.charAt(cntr); 450 451 if (c < 32) { 452 result.append('\\'); 453 454 String v = Integer.toHexString(c); 455 456 result.append("0000".substring(0, 4 - v.length())); 457 result.append(v); 458 } else { 459 result.append(c); 460 } 461 } 462 463 output.append(result.toString()); 464 } 465 466 private static void dumpName(PrintWriter output, CharSequence name) { 467 output.append('N'); 468 output.append(name.toString()); 469 output.append(';'); 470 } 471 472 private static void dumpTypeVariables(SymbolDumper dumper, List <? extends TypeVariable> params) { 473 if (params.isEmpty()) 474 return ; 475 476 dumper.output.append('<'); 477 478 dumper.visit(params, Boolean.TRUE); 479 480 dumper.output.append('>'); 481 } 482 483 private static void dumpFlags(PrintWriter output, long flags) { 484 output.append('M'); 485 output.append(Long.toHexString(flags)); 486 output.append(';'); 487 } 488 489 private static void dumpAnnotations(SymbolDumper d, Element e) { 490 for (AnnotationMirror m : e.getAnnotationMirrors()) { 491 dumpAnnotation(d, m); 492 } 493 494 d.output.append(';'); 495 } 496 497 private static void dumpAnnotation(SymbolDumper d, AnnotationMirror m) { 498 d.visit(m.getAnnotationType()); 499 500 for (Entry<? extends ExecutableElement, ? extends AnnotationValue> entry : m.getElementValues().entrySet()) { 501 dumpName(d.output, entry.getKey().getSimpleName().toString()); 502 new AnnotationValueVisitorImpl().visit(entry.getValue(), d); 503 } 504 505 d.output.append(';'); 506 } 507 508 private static class AnnotationValueVisitorImpl extends SimpleAnnotationValueVisitor6<Void , SymbolDumper> { 509 510 @Override 511 public Void visitBoolean(boolean b, SymbolDumper d) { 512 d.output.append('Z'); d.output.append(String.valueOf(b)); 514 d.output.append(';'); 515 516 return null; 517 } 518 519 @Override 520 public Void visitByte(byte b, SymbolDumper d) { 521 d.output.append('B'); d.output.append(String.valueOf(b)); 523 d.output.append(';'); 524 525 return null; 526 } 527 528 @Override 529 public Void visitChar(char c, SymbolDumper d) { 530 d.output.append('C'); appendEscapedString(d.output, String.valueOf(c)); 532 d.output.append(';'); 533 534 return null; 535 } 536 537 @Override 538 public Void visitDouble(double v, SymbolDumper d) { 539 d.output.append('D'); d.output.append(String.valueOf(v)); 541 d.output.append(';'); 542 543 return null; 544 } 545 546 @Override 547 public Void visitFloat(float f, SymbolDumper d) { 548 d.output.append('F'); d.output.append(String.valueOf(f)); 550 d.output.append(';'); 551 552 return null; 553 } 554 555 @Override 556 public Void visitInt(int i, SymbolDumper d) { 557 d.output.append('I'); d.output.append(String.valueOf(i)); 559 d.output.append(';'); 560 561 return null; 562 } 563 564 @Override 565 public Void visitLong(long i, SymbolDumper d) { 566 d.output.append('J'); d.output.append(String.valueOf(i)); 568 d.output.append(';'); 569 570 return null; 571 } 572 573 @Override 574 public Void visitShort(short s, SymbolDumper d) { 575 d.output.append('S'); d.output.append(String.valueOf(s)); 577 d.output.append(';'); 578 579 return null; 580 } 581 582 @Override 583 public Void visitString(String s, SymbolDumper d) { 584 d.output.append('L'); 585 appendEscapedString(d.output, String.valueOf(s)); 586 d.output.append(';'); 587 588 return null; 589 } 590 591 @Override 592 public Void visitType(TypeMirror t, SymbolDumper p) { 593 p.output.append('Y'); 594 p.visit(t); 595 596 return null; 597 } 598 599 @Override 600 public Void visitEnumConstant(VariableElement c, SymbolDumper d) { 601 d.output.append('O'); 602 d.visit(c.getEnclosingElement().asType()); 603 dumpName(d.output, c.getSimpleName()); 604 605 return null; 606 } 607 608 @Override 609 public Void visitAnnotation(AnnotationMirror a, SymbolDumper d) { 610 d.output.append('P'); 611 dumpAnnotation(d, a); 612 613 return null; 614 } 615 616 @Override 617 public Void visitArray(List <? extends AnnotationValue> vals, SymbolDumper d) { 618 d.output.append('['); 619 for (AnnotationValue v : vals) { 620 visit(v, d); 621 } 622 d.output.append(';'); 623 624 return null; 625 } 626 627 @Override 628 public Void visitUnknown(AnnotationValue av, SymbolDumper p) { 629 throw new UnsupportedOperationException ("SymbolDumper should be fixed to incorporate unknown value: " + av); 630 } 631 632 } 633 634 } 635 | Popular Tags |