1package annotator.find; 2 3import java.util.AbstractSet; 4import java.util.ArrayDeque; 5import java.util.ArrayList; 6import java.util.Collection; 7import java.util.Collections; 8import java.util.Comparator; 9import java.util.Deque; 10import java.util.HashMap; 11import java.util.Iterator; 12import java.util.LinkedHashSet; 13import java.util.List; 14import java.util.Map; 15import java.util.NoSuchElementException; 16import java.util.Set; 17import java.util.SortedMap; 18import java.util.TreeMap; 19import java.util.TreeSet; 20 21import javax.lang.model.element.Name; 22import javax.lang.model.type.TypeKind; 23 24import annotations.el.InnerTypeLocation; 25import annotations.io.ASTIndex; 26import annotations.io.ASTPath; 27import annotations.io.ASTRecord; 28import type.*; 29 30import com.sun.source.tree.AnnotatedTypeTree; 31import com.sun.source.tree.AnnotationTree; 32import com.sun.source.tree.ArrayTypeTree; 33import com.sun.source.tree.CompilationUnitTree; 34import com.sun.source.tree.ExpressionTree; 35import com.sun.source.tree.IdentifierTree; 36import com.sun.source.tree.MemberSelectTree; 37import com.sun.source.tree.NewArrayTree; 38import com.sun.source.tree.ParameterizedTypeTree; 39import com.sun.source.tree.PrimitiveTypeTree; 40import com.sun.source.tree.Tree; 41import com.sun.source.tree.TreeVisitor; 42import com.sun.source.tree.TypeParameterTree; 43import com.sun.source.tree.WildcardTree; 44import com.sun.source.util.TreePath; 45import com.sun.tools.javac.code.Kinds; 46import com.sun.tools.javac.code.Symbol.ClassSymbol; 47import com.sun.tools.javac.code.Symbol.MethodSymbol; 48import com.sun.tools.javac.code.TypeAnnotationPosition.TypePathEntry; 49import com.sun.tools.javac.code.TypeAnnotationPosition.TypePathEntryKind; 50import com.sun.tools.javac.code.TypeTag; 51import com.sun.tools.javac.tree.JCTree; 52import com.sun.tools.javac.tree.JCTree.JCExpression; 53import com.sun.tools.javac.util.Pair; 54 55/** 56 * @author dbro 57 * 58 * An indexed collection (though not {@link java.util.Collection}, only 59 * {@link java.lang.Iterable}) of {@link Insertion}s with methods to 60 * select those specified for a given class or for an outer class along 61 * with its local classes. This class is especially useful when a 62 * single JAIF stores annotations for many source files, as it reduces 63 * the number of insertions to be considered for any AST node. 64 * 65 * The class now serves a second purpose, which should probably be 66 * separated out (according to OO dogma, at least): It attaches 67 * {@link annotations.io.ASTPath}-based inner type {@link Insertion}s to 68 * a {@link TypedInsertion} on the outer type if one exists (see 69 * {@link #organizeTypedInsertions(CompilationUnitTree, String, Collection)}. 70 * Since getting these insertions right depends on this organization, 71 * this class is now essential for correctness, not merely for 72 * performance. 73 */ 74public class Insertions implements Iterable<Insertion> { 75 private static int kindLevel(Insertion i) { 76 // ordered so insertion that depends on another gets inserted after other 77 switch (i.getKind()) { 78 case CONSTRUCTOR: 79 return 3; 80 case NEW: 81 case RECEIVER: 82 return 2; 83 case CAST: 84 return 1; 85 // case ANNOTATION: 86 // case CLOSE_PARENTHESIS: 87 default: 88 return 0; 89 } 90 } 91 92 private static final Comparator<Insertion> byASTRecord = 93 new Comparator<Insertion>() { 94 @Override 95 public int compare(Insertion o1, Insertion o2) { 96 Criteria c1 = o1.getCriteria(); 97 Criteria c2 = o2.getCriteria(); 98 ASTPath p1 = c1.getASTPath(); 99 ASTPath p2 = c2.getASTPath(); 100 ASTRecord r1 = new ASTRecord(null, 101 c1.getClassName(), c1.getMethodName(), c1.getFieldName(), 102 p1 == null ? ASTPath.empty() : p1); 103 ASTRecord r2 = new ASTRecord(null, 104 c2.getClassName(), c2.getMethodName(), c2.getFieldName(), 105 p2 == null ? ASTPath.empty() : p2); 106 int c = r1.compareTo(r2); 107 if (c == 0) { 108 // c = o1.getKind().compareTo(o2.getKind()); 109 c = Integer.compare(kindLevel(o2), kindLevel(o1)); // descending 110 if (c == 0) { c = o1.toString().compareTo(o2.toString()); } 111 } 112 return c; 113 } 114 }; 115 116 // store indexes insertions by (qualified) outer class name and inner 117 // class path (if any) 118 private Map<String, Map<String, Set<Insertion>>> store; 119 private int size; 120 121 private Pair<String, String> nameSplit(String name) { 122 int i = name.indexOf('$'); // FIXME: don't split on '$' in source 123 return i < 0 124 ? Pair.of(name, "") 125 : Pair.of(name.substring(0, i), name.substring(i)); 126 } 127 128 public Insertions() { 129 store = new HashMap<String, Map<String, Set<Insertion>>>(); 130 size = 0; 131 } 132 133 // auxiliary for following two methods 134 private void forClass(CompilationUnitTree cut, 135 String qualifiedClassName, Set<Insertion> result) { 136 Pair<String, String> pair = nameSplit(qualifiedClassName); 137 Map<String, Set<Insertion>> map = store.get(pair.fst); 138 if (map != null) { 139 Set<Insertion> set = new TreeSet<Insertion>(byASTRecord); 140 set.addAll(map.get(pair.snd)); 141 if (set != null) { 142 set = organizeTypedInsertions(cut, qualifiedClassName, set); 143 result.addAll(set); 144 } 145 } 146 } 147 148 /** 149 * Selects {@link Insertion}s relevant to a given class. 150 * 151 * @param cut the current compilation unit 152 * @param qualifiedClassName the fully qualified class name 153 * @return {@link java.util.Set} of {@link Insertion}s with an 154 * {@link InClassCriterion} for the given class 155 */ 156 public Set<Insertion> forClass(CompilationUnitTree cut, 157 String qualifiedClassName) { 158 Set<Insertion> set = new LinkedHashSet<Insertion>(); 159 forClass(cut, qualifiedClassName, set); 160 return set; 161 } 162 163 /** 164 * Selects {@link Insertion}s relevant to a given outer class and its 165 * local classes. 166 * 167 * @param cut the current compilation unit 168 * @param qualifiedOuterClassName the fully qualified outer class name 169 * @return {@link java.util.Set} of {@link Insertion}s with an 170 * {@link InClassCriterion} for the given outer class or one 171 * of its local classes 172 */ 173 public Set<Insertion> forOuterClass(CompilationUnitTree cut, 174 String qualifiedOuterClassName) { 175 Map<String, Set<Insertion>> map = store.get(qualifiedOuterClassName); 176 if (map == null || map.isEmpty()) { 177 return Collections.<Insertion>emptySet(); 178 } else { 179 Set<Insertion> set = new LinkedHashSet<Insertion>(); 180 for (String key : map.keySet()) { 181 String qualifiedClassName = qualifiedOuterClassName + key; 182 forClass(cut, qualifiedClassName, set); 183 } 184 return set; 185 } 186 } 187 188 /** 189 * Add an {@link Insertion} to this collection. 190 */ 191 public void add(Insertion ins) { 192 InClassCriterion icc = ins.getCriteria().getInClass(); 193 String k1 = ""; 194 String k2 = ""; 195 Map<String, Set<Insertion>> map; 196 Set<Insertion> set; 197 198 if (icc != null) { 199 Pair<String, String> triple = nameSplit(icc.className); 200 k1 = triple.fst; 201 k2 = triple.snd; 202 } 203 map = store.get(k1); 204 if (map == null) { 205 map = new HashMap<String, Set<Insertion>>(); 206 store.put(k1, map); 207 } 208 set = map.get(k2); 209 if (set == null) { 210 set = new LinkedHashSet<Insertion>(); 211 map.put(k2, set); 212 } 213 214 size -= set.size(); 215 set.add(ins); 216 size += set.size(); 217 } 218 219 /** 220 * Add all {@link Insertion}s in the given 221 * {@link java.util.Collection} to this collection. 222 */ 223 public void addAll(Collection<? extends Insertion> c) { 224 for (Insertion ins : c) { 225 add(ins); 226 } 227 } 228 229 /** 230 * Returns the number of {@link Insertion}s in this collection. 231 */ 232 public int size() { 233 return size; 234 } 235 236 @Override 237 public Iterator<Insertion> iterator() { 238 return new Iterator<Insertion>() { 239 private Iterator<Map<String, Set<Insertion>>> miter = 240 store.values().iterator(); 241 private Iterator<Set<Insertion>> siter = 242 Collections.<Set<Insertion>>emptySet().iterator(); 243 private Iterator<Insertion> iiter = 244 Collections.<Insertion>emptySet().iterator(); 245 246 @Override 247 public boolean hasNext() { 248 if (iiter.hasNext()) { return true; } 249 while (siter.hasNext()) { 250 iiter = siter.next().iterator(); 251 if (iiter.hasNext()) { return true; } 252 } 253 while (miter.hasNext()) { 254 siter = miter.next().values().iterator(); 255 while (siter.hasNext()) { 256 iiter = siter.next().iterator(); 257 if (iiter.hasNext()) { return true; } 258 } 259 } 260 return false; 261 } 262 263 @Override 264 public Insertion next() { 265 if (hasNext()) { return iiter.next(); } 266 throw new NoSuchElementException(); 267 } 268 269 @Override 270 public void remove() { 271 throw new UnsupportedOperationException(); 272 } 273 }; 274 } 275 276 /** 277 * Returns a {@link java.util.List} containing all {@link Insertion}s 278 * in this collection. 279 */ 280 public List<Insertion> toList() { 281 List<Insertion> list = new ArrayList<Insertion>(size); 282 for (Insertion ins : this) { list.add(ins); } 283 return null; 284 } 285 286 /* 287 * This method detects inner type relationships among ASTPath-based 288 * insertion specifications and organizes the insertions accordingly. 289 * This step is necessary because 1) insertion proceeds from the end to 290 * the beginning of the source and 2) the insertion location does not 291 * always exist prior to the top-level type insertion. 292 */ 293 private Set<Insertion> organizeTypedInsertions(CompilationUnitTree cut, 294 String className, Collection<Insertion> insertions) { 295 ASTRecordMap<TypedInsertion> map = new ASTRecordMap<TypedInsertion>(); 296 Set<Insertion> organized = new LinkedHashSet<Insertion>(); 297 Set<Insertion> unorganized = new LinkedHashSet<Insertion>(); 298 List<Insertion> list = new ArrayList<Insertion>(); 299 300 // First divide the insertions into three buckets: TypedInsertions 301 // on outer types (map), ASTPath-based insertions on local types 302 // (unorganized -- built as list and then sorted, since building as 303 // a set spuriously removes "duplicates" according to the 304 // comparator), and everything else (organized -- where all 305 // eventually land). 306 for (Insertion ins : insertions) { 307 if (ins.getInserted()) { continue; } 308 Criteria criteria = ins.getCriteria(); 309 GenericArrayLocationCriterion galc = 310 criteria.getGenericArrayLocation(); 311 ASTPath p = criteria.getASTPath(); 312 if (p == null || p.isEmpty() 313 || galc != null && !galc.getLocation().isEmpty() 314 || ins instanceof CastInsertion 315 || ins instanceof CloseParenthesisInsertion) { 316 organized.add(ins); 317 } else { 318 ASTRecord rec = new ASTRecord(cut, criteria.getClassName(), 319 criteria.getMethodName(), criteria.getFieldName(), p); 320 ASTPath.ASTEntry entry = rec.astPath.get(-1); 321 Tree node; 322 323 if (entry.getTreeKind() == Tree.Kind.NEW_ARRAY 324 && entry.childSelectorIs(ASTPath.TYPE) 325 && entry.getArgument() == 0) { 326 ASTPath temp = rec.astPath.getParentPath(); 327 node = ASTIndex.getNode(cut, rec.replacePath(temp)); 328 node = node instanceof JCTree.JCNewArray 329 ? TypeTree.fromType(((JCTree.JCNewArray) node).type) 330 : null; 331 } else { 332 node = ASTIndex.getNode(cut, rec); 333 } 334 335 if (ins instanceof TypedInsertion) { 336 TypedInsertion tins = map.get(rec); 337 if (ins instanceof NewInsertion) { 338 NewInsertion nins = (NewInsertion) ins; 339 if (entry.getTreeKind() == Tree.Kind.NEW_ARRAY 340 && entry.childSelectorIs(ASTPath.TYPE)) { 341 int a = entry.getArgument(); 342 List<TypePathEntry> loc0 = new ArrayList<TypePathEntry>(a); 343 ASTRecord rec0 = null; 344 if (a == 0) { 345 rec0 = rec.replacePath(p.getParentPath()); 346 Tree t = ASTIndex.getNode(cut, rec0); 347 if (t == null || t.toString().startsWith("{")) { 348 rec0 = null; 349 } else { 350 rec = rec0; 351 rec0 = rec.extend(Tree.Kind.NEW_ARRAY, 352 ASTPath.TYPE, 0); 353 } 354 } else if (node != null 355 && !nins.getInnerTypeInsertions().isEmpty()) { 356 if (node.getKind() == Tree.Kind.IDENTIFIER) { 357 node = ASTIndex.getNode(cut, 358 rec.replacePath(p.getParentPath())); 359 } 360 if ((node.getKind() == Tree.Kind.NEW_ARRAY 361 || node.getKind() == Tree.Kind.ARRAY_TYPE) 362 && !node.toString().startsWith("{")) { 363 rec = rec.replacePath(p.getParentPath()); 364 365 Collections.fill(loc0, TypePathEntry.ARRAY); 366 // irec = rec; 367 // if (node.getKind() == Tree.Kind.NEW_ARRAY) { 368 rec0 = rec.extend(Tree.Kind.NEW_ARRAY, 369 ASTPath.TYPE, 0); 370 // } 371 } 372 } 373 374 if (rec0 != null) { 375 for (Insertion inner : nins.getInnerTypeInsertions()) { 376 Criteria icriteria = inner.getCriteria(); 377 GenericArrayLocationCriterion igalc = 378 icriteria.getGenericArrayLocation(); 379 if (igalc != null) { 380 ASTRecord rec1; 381 int b = igalc.getLocation().size(); 382 List<TypePathEntry> loc = 383 new ArrayList<TypePathEntry>(a + b); 384 loc.addAll(loc0); 385 loc.addAll(igalc.getLocation()); 386 rec1 = extendToInnerType(rec0, loc, node); 387 icriteria.add(new GenericArrayLocationCriterion()); 388 icriteria.add(new ASTPathCriterion(rec1.astPath)); 389 inner.setInserted(false); 390 organized.add(inner); 391 } 392 } 393 nins.getInnerTypeInsertions().clear(); 394 } 395 } 396 } 397 if (tins == null) { 398 map.put(rec, (TypedInsertion) ins); 399 } else if (tins.getType().equals(((TypedInsertion) ins).getType())) { 400 mergeTypedInsertions(tins, (TypedInsertion) ins); 401 } 402 } else { 403 int d = newArrayInnerTypeDepth(p); 404 if (d > 0) { 405 ASTPath temp = p; 406 while (!temp.isEmpty() 407 && (node == null || node.getKind() != Tree.Kind.NEW_ARRAY)) { 408 // TODO: avoid repeating work of newArrayInnerTypeDepth() 409 temp = temp.getParentPath(); 410 node = ASTIndex.getNode(cut, rec.replacePath(temp)); 411 } 412 if (node == null) { 413 // TODO: ??? 414 } 415 temp = temp.extend( 416 new ASTPath.ASTEntry(Tree.Kind.NEW_ARRAY, ASTPath.TYPE, 0)); 417 if (node.toString().startsWith("{")) { 418 TypedInsertion tins = map.get(rec.replacePath(temp)); 419 if (tins == null) { 420 // TODO 421 } else { 422 tins.getInnerTypeInsertions().add(ins); 423 ins.setInserted(true); 424 } 425 } else { 426 List<? extends ExpressionTree> dims = 427 ((NewArrayTree) node).getDimensions(); 428 ASTRecord irec = rec.replacePath(p.getParentPath()) 429 .extend(Tree.Kind.NEW_ARRAY, ASTPath.TYPE, 0); 430 GenericArrayLocationCriterion igalc = 431 criteria.getGenericArrayLocation(); 432 for (int i = 0 ; i < d; i++) { 433 irec = irec.extend(Tree.Kind.ARRAY_TYPE, ASTPath.TYPE); 434 } 435 if (igalc != null) { 436 List<TypePathEntry> loc = igalc.getLocation(); 437 if (!loc.isEmpty()) { 438 try { 439 Tree dim = dims.get(d-1); 440 irec = extendToInnerType(irec, loc, dim); 441 criteria.add(new ASTPathCriterion(irec.astPath)); 442 criteria.add(new GenericArrayLocationCriterion()); 443 } catch (RuntimeException e) {} 444 } 445 } 446 } 447 } 448 list.add(ins); 449 } 450 } 451 } 452 // if (map.isEmpty()) { 453 // organized.addAll(unorganized); 454 // return organized; 455 // } 456 Collections.sort(list, byASTRecord); 457 unorganized.addAll(list); 458 459 // Each Insertion in unorganized gets attached to a TypedInsertion 460 // in map if possible; otherwise, it gets dumped into organized. 461 for (Insertion ins : unorganized) { 462 Criteria criteria = ins.getCriteria(); 463 String methodName = criteria.getMethodName(); 464 String fieldName = criteria.getFieldName(); 465 ASTPath ap1 = criteria.getASTPath(); 466 List<TypePathEntry> tpes = new ArrayList<TypePathEntry>(); 467 if (ap1 == null) { 468 // || methodName == null && fieldName == null) 469 organized.add(ins); 470 continue; 471 } 472 473 // First find the relevant "top-level" insertion, if any. 474 // ap0: path to top-level type; ap1: path to local type 475 ASTRecord rec; 476 Tree.Kind kind; 477 Deque<ASTPath> astack = new ArrayDeque<ASTPath>(ap1.size()); 478 ASTPath ap0 = ap1; 479 do { 480 astack.push(ap0); 481 ap0 = ap0.getParentPath(); 482 } while (!ap0.isEmpty()); 483 do { 484 ap0 = astack.pop(); 485 kind = ap0.get(-1).getTreeKind(); 486 rec = new ASTRecord(cut, className, methodName, fieldName, ap0); 487 } while (!(astack.isEmpty() || map.containsKey(rec))); 488 489 TypedInsertion tins = map.get(rec); 490 TreePath path = ASTIndex.getTreePath(cut, rec); 491 Tree node = path == null ? null : path.getLeaf(); 492 if (node == null && ap0.isEmpty()) { 493 organized.add(ins); 494 continue; 495 } 496 497 // Try to create a top-level insertion if none exists (e.g., if 498 // there is an insertion for NewArray.type 1 but not for 0). 499 if (tins == null) { 500 GenericArrayLocationCriterion galc = 501 criteria.getGenericArrayLocation(); 502 if (node == null) { 503 // TODO: figure out from rec? 504 organized.add(ins); 505 continue; 506 } else { 507 Tree t = path.getLeaf(); 508 switch (t.getKind()) { 509 case NEW_ARRAY: 510 int d = 0; 511 ASTPath.ASTEntry e = ap1.get(-1); 512 List<TypePathEntry> loc = null; 513 List<Insertion> inners = new ArrayList<Insertion>(); 514 Type type = TypeTree.conv(((JCTree.JCNewArray) t).type); 515 if (e.getTreeKind() == Tree.Kind.NEW_ARRAY) { 516 d += e.getArgument(); 517 } 518 if (galc != null) { 519 loc = galc.getLocation(); 520 int n = loc.size(); 521 while (--n >= 0 && loc.get(n).tag == TypePathEntryKind.ARRAY) { 522 ++d; 523 } 524 loc = n < 0 ? null : loc.subList(0, ++n); 525 } 526 criteria.add(new ASTPathCriterion( 527 rec.astPath.getParentPath().extendNewArray(d))); 528 criteria.add(loc == null || loc.isEmpty() 529 ? new GenericArrayLocationCriterion() 530 : new GenericArrayLocationCriterion( 531 new InnerTypeLocation(loc))); 532 inners.add(ins); 533 tins = new NewInsertion(type, criteria, inners); 534 tins.setInserted(true); 535 map.put(rec, tins); 536 break; 537 default: 538 break; 539 } 540 path = path.getParentPath(); 541 } 542 } 543 544 // The sought node may or may not be found in the tree; if not, it 545 // may need to be created later. Use whatever part of the path 546 // exists already to distinguish MEMBER_SELECT nodes that indicate 547 // qualifiers from those that indicate local types. Assume any 548 // MEMBER_SELECTs in the AST path that don't correspond to 549 // existing nodes are part of a type use. 550 if (node == null) { 551 ASTPath ap = ap0; 552 if (!ap.isEmpty()) { 553 do { 554 ap = ap.getParentPath(); 555 node = ASTIndex.getNode(cut, rec.replacePath(ap)); 556 } while (node == null && !ap.isEmpty()); 557 } 558 if (node == null) { 559 organized.add(ins); 560 continue; 561 } 562 563 // find actual type 564 ClassSymbol csym = null; 565 switch (tins.getKind()) { 566 case CONSTRUCTOR: 567 if (node instanceof JCTree.JCMethodDecl) { 568 MethodSymbol msym = ((JCTree.JCMethodDecl) node).sym; 569 csym = (ClassSymbol) msym.owner; 570 node = TypeTree.fromType(csym.type); 571 break; 572 } else if (node instanceof JCTree.JCClassDecl) { 573 csym = ((JCTree.JCClassDecl) node).sym; 574 if (csym.owner instanceof ClassSymbol) { 575 csym = (ClassSymbol) csym.owner; 576 node = TypeTree.fromType(csym.type); 577 break; 578 } 579 } 580 throw new RuntimeException(); 581 case NEW: 582 if (node instanceof JCTree.JCNewArray) { 583 if (node.toString().startsWith("{")) { 584 node = TypeTree.fromType(((JCTree.JCNewArray) node).type); 585 break; 586 } else { 587 organized.add(ins); 588 continue; 589 } 590 } 591 throw new RuntimeException(); 592 case RECEIVER: 593 if (node instanceof JCTree.JCMethodDecl) { 594 JCTree.JCMethodDecl jmd = (JCTree.JCMethodDecl) node; 595 csym = (ClassSymbol) jmd.sym.owner; 596 if ("<init>".equals(jmd.name.toString())) { 597 csym = (ClassSymbol) csym.owner; 598 } 599 } else if (node instanceof JCTree.JCClassDecl) { 600 csym = ((JCTree.JCClassDecl) node).sym; 601 } 602 if (csym != null) { 603 node = TypeTree.fromType(csym.type); 604 break; 605 } 606 throw new RuntimeException(); 607 default: 608 throw new RuntimeException(); 609 } 610 } 611 612 /* 613 * Inner types require special consideration due to the 614 * structural differences between an AST that represents a type 615 * (subclass of com.sun.source.Tree) and the type's logical 616 * representation (subclass of type.Type). The differences are 617 * most prominent in the case of a type with a parameterized 618 * local type. For example, the AST for A.B.C<D> looks like 619 * this: 620 * 621 * ParameterizedType 622 * / \ 623 * MemberSelect Identifier 624 * / \ | 625 * MemberSelect (Name) D 626 * / \ | 627 * Identifier (Name) C 628 * | | 629 * A B 630 * 631 * (Technically, the Names are not AST nodes but rather 632 * attributes of their parent MemberSelect nodes.) The logical 633 * representation seems more intuitive: 634 * 635 * DeclaredType 636 * / | \ 637 * Name Params Inner 638 * | | | 639 * A - DeclaredType 640 * / | \ 641 * Name Params Inner 642 * | | | 643 * B - DeclaredType 644 * / | \ 645 * Name Params Inner 646 * | | | 647 * C D - 648 * 649 * The opposing "chirality" of local type nesting means that the 650 * usual recursive descent strategy doesn't work for finding a 651 * logical type path in an AST; in effect, local types have to 652 * be "turned inside-out". 653 * 654 * Worse yet, the actual tree structure may not exist in the tree! 655 * It is possible to recover the actual type from the symbol 656 * table, but the methods to create AST nodes are not visible 657 * here. Hence, the conversion relies on custom implementations 658 * of the interfaces in com.sun.source.tree.Tree, which are 659 * defined in the local class TypeTree. 660 */ 661 int i = ap0.size(); 662 int n = ap1.size(); 663 int actualDepth = 0; // inner type levels seen 664 int expectedDepth = 0; // inner type levels anticipated 665 666 // skip any declaration nodes 667 while (i < n) { 668 ASTPath.ASTEntry entry = ap1.get(i); 669 kind = entry.getTreeKind(); 670 if (kind != Tree.Kind.METHOD && kind != Tree.Kind.VARIABLE) { 671 break; 672 } 673 ++i; 674 } 675 676 // now build up the type path in JVM's format 677 while (i < n) { 678 ASTPath.ASTEntry entry = ap1.get(i); 679 rec = rec.extend(entry); 680 kind = entry.getTreeKind(); 681 682 while (node.getKind() == Tree.Kind.ANNOTATED_TYPE) { // skip 683 node = ((AnnotatedTypeTree) node).getUnderlyingType(); 684 } 685 if (expectedDepth == 0) { 686 expectedDepth = localDepth(node); 687 } 688 689 switch (kind) { 690 case ARRAY_TYPE: 691 if (expectedDepth == 0 && node.getKind() == kind) { 692 node = ((ArrayTypeTree) node).getType(); 693 while (--actualDepth >= 0) { 694 tpes.add(TypePathEntry.INNER_TYPE); 695 } 696 tpes.add(TypePathEntry.ARRAY); 697 break; 698 } 699 throw new RuntimeException(); 700 701 case MEMBER_SELECT: 702 if (--expectedDepth >= 0) { // otherwise, shouldn't have MEMBER_SELECT 703 node = ((MemberSelectTree) node).getExpression(); 704 ++actualDepth; 705 break; 706 } 707 throw new RuntimeException(); 708 709 case NEW_ARRAY: 710 assert tpes.isEmpty(); 711 ap0 = ap0.add(new ASTPath.ASTEntry(Tree.Kind.NEW_ARRAY, 712 ASTPath.TYPE, 0)); 713 if (expectedDepth == 0 && node.getKind() == kind) { 714 if (node instanceof JCTree.JCNewArray) { 715 int arg = entry.getArgument(); 716 if (arg > 0) { 717 node = ((JCTree.JCNewArray) node).elemtype; 718 tpes.add(TypePathEntry.ARRAY); 719 while (--arg > 0 && node instanceof JCTree.JCArrayTypeTree) { 720 node = ((JCTree.JCArrayTypeTree) node).elemtype; 721 tpes.add(TypePathEntry.ARRAY); 722 } 723 if (arg > 0) { throw new RuntimeException(); } 724 } else { 725 node = TypeTree.fromType(((JCTree.JCNewArray) node).type); 726 } 727 } else { 728 throw new RuntimeException("NYI"); // TODO 729 } 730 break; 731 } 732 throw new RuntimeException(); 733 734 case PARAMETERIZED_TYPE: 735 if (node.getKind() == kind) { 736 ParameterizedTypeTree ptt = (ParameterizedTypeTree) node; 737 if (entry.childSelectorIs(ASTPath.TYPE)) { 738 node = ptt.getType(); 739 break; // ParameterizedType.type is "transparent" wrt type path 740 } else if (expectedDepth == 0 741 && entry.childSelectorIs(ASTPath.TYPE_ARGUMENT)) { 742 List<? extends Tree> typeArgs = ptt.getTypeArguments(); 743 int j = entry.getArgument(); 744 if (j >= 0 && j < typeArgs.size()) { 745 // make sure any inner types are accounted for 746 actualDepth = 0; 747 expectedDepth = localDepth(ptt.getType()); 748 while (--expectedDepth >= 0) { 749 tpes.add(TypePathEntry.INNER_TYPE); 750 } 751 node = typeArgs.get(j); 752 tpes.add( 753 new TypePathEntry(TypePathEntryKind.TYPE_ARGUMENT, j)); 754 break; 755 } 756 } 757 } 758 throw new RuntimeException(); 759 760 case UNBOUNDED_WILDCARD: 761 if (ASTPath.isWildcard(node.getKind())) { 762 if (expectedDepth == 0 763 && (i < 1 764 || ap1.get(i-1).getTreeKind() != Tree.Kind.INSTANCE_OF) 765 && (i < 2 766 || ap1.get(i-2).getTreeKind() != Tree.Kind.ARRAY_TYPE)) { 767 while (--actualDepth >= 0) { 768 tpes.add(TypePathEntry.INNER_TYPE); 769 } 770 tpes.add(TypePathEntry.WILDCARD); 771 break; 772 } 773 } 774 throw new RuntimeException(); 775 776 default: 777 node = ASTIndex.getNode(cut, rec); 778 break; 779 } 780 781 ++i; 782 } 783 784 while (--actualDepth >= 0) { 785 tpes.add(TypePathEntry.INNER_TYPE); 786 } 787 788 organized.add(ins); 789 if (tpes.isEmpty()) { 790 // assert ap1.equals(ap0) && !map.containsKey(ap0); 791// organized.add(ins); 792 // map.put(rec, (TypedInsertion) ins); 793 } else { 794 criteria.add(new ASTPathCriterion(ap0)); 795 criteria.add(new GenericArrayLocationCriterion( 796 new InnerTypeLocation(tpes))); 797 tins.getInnerTypeInsertions().add(ins); 798 } 799 } 800 organized.addAll(map.values()); 801 return organized; 802 } 803 804 private int newArrayInnerTypeDepth(ASTPath path) { 805 int d = 0; 806 if (path != null) { 807 while (!path.isEmpty()) { 808 ASTPath.ASTEntry entry = path.get(-1); 809 switch (entry.getTreeKind()) { 810 case ANNOTATED_TYPE: 811 case MEMBER_SELECT: 812 case PARAMETERIZED_TYPE: 813 case UNBOUNDED_WILDCARD: 814 d = 0; 815 break; 816 case ARRAY_TYPE: 817 ++d; 818 break; 819 case NEW_ARRAY: 820 if (entry.childSelectorIs(ASTPath.TYPE) && entry.hasArgument()) { 821 d += entry.getArgument(); 822 } 823 return d; 824 default: 825 return 0; 826 } 827 path = path.getParentPath(); 828 } 829 } 830 return 0; 831 } 832 833 /** 834 * Find an {@link ASTRecord} for the tree corresponding to a nested 835 * type of the type (use) to which the given record corresponds. 836 * 837 * @param rec record of (outer) type AST to be annotated 838 * @param loc inner type path 839 * @return record that locates the (nested) type in the source 840 */ 841 private ASTRecord extendToInnerType(ASTRecord rec, List<TypePathEntry> loc) { 842 ASTRecord r = rec; 843 Iterator<TypePathEntry> iter = loc.iterator(); 844 int depth = 0; 845 846 while (iter.hasNext()) { 847 TypePathEntry tpe = iter.next(); 848 switch (tpe.tag) { 849 case ARRAY: 850 while (depth-- > 0) { 851 r = r.extend(Tree.Kind.MEMBER_SELECT, ASTPath.EXPRESSION); 852 } 853 r = r.extend(Tree.Kind.ARRAY_TYPE, ASTPath.TYPE); 854 break; 855 case INNER_TYPE: 856 ++depth; 857 break; 858 case TYPE_ARGUMENT: 859 depth = 0; 860 r = r.extend(Tree.Kind.PARAMETERIZED_TYPE, ASTPath.TYPE_ARGUMENT, 861 tpe.arg); 862 break; 863 case WILDCARD: 864 while (depth-- > 0) { 865 r = r.extend(Tree.Kind.MEMBER_SELECT, ASTPath.EXPRESSION); 866 } 867 r = r.extend(Tree.Kind.UNBOUNDED_WILDCARD, ASTPath.BOUND); 868 break; 869 default: 870 throw new RuntimeException(); 871 } 872 } 873 while (depth-- > 0) { 874 r = r.extend(Tree.Kind.MEMBER_SELECT, ASTPath.EXPRESSION); 875 } 876 return r; 877 } 878 879 /** 880 * Find an {@link ASTRecord} for the tree corresponding to a nested 881 * type of the type (use) to which the given tree and record 882 * correspond. 883 * 884 * @param rec record that locates {@code node} in the source 885 * @param loc inner type path 886 * @param node starting point for inner type path 887 * @return record that locates the nested type in the source 888 */ 889 private ASTRecord extendToInnerType(ASTRecord rec, 890 List<TypePathEntry> loc, Tree node) { 891 ASTRecord r = rec; 892 Tree t = node; 893 Iterator<TypePathEntry> iter = loc.iterator(); 894 TypePathEntry tpe = iter.next(); 895 896outer: 897 while (true) { 898 int d = localDepth(node); 899 900 switch (t.getKind()) { 901 case ANNOTATED_TYPE: 902 r = r.extend(Tree.Kind.ANNOTATED_TYPE, ASTPath.TYPE); 903 t = ((JCTree.JCAnnotatedType) t).getUnderlyingType(); 904 break; 905 906 case ARRAY_TYPE: 907 if (d == 0 && tpe.tag == TypePathEntryKind.ARRAY) { 908 int a = 0; 909 if (!r.astPath.isEmpty()) { 910 ASTPath.ASTEntry e = r.astPath.get(-1); 911 if (e.getTreeKind() == Tree.Kind.NEW_ARRAY 912 && e.childSelectorIs(ASTPath.TYPE)) { 913 a = 1 + e.getArgument(); 914 } 915 } 916 r = a > 0 917 ? r.replacePath(r.astPath.getParentPath()) 918 .extend(Tree.Kind.NEW_ARRAY, ASTPath.TYPE, a) 919 : r.extend(Tree.Kind.ARRAY_TYPE, ASTPath.TYPE); 920 t = ((ArrayTypeTree) t).getType(); 921 break; 922 } 923 throw new RuntimeException(); 924 925 case MEMBER_SELECT: 926 if (d > 0 && tpe.tag == TypePathEntryKind.INNER_TYPE) { 927 Tree temp = t; 928 do { 929 temp = ((JCTree.JCFieldAccess) temp).getExpression(); 930 if (!iter.hasNext()) { 931 do { 932 r = r.extend(Tree.Kind.MEMBER_SELECT, ASTPath.EXPRESSION); 933 } while (--d > 0); 934 return r; 935 } 936 tpe = iter.next(); 937 if (--d == 0) { 938 continue outer; // avoid next() at end of loop 939 } 940 } while (tpe.tag == TypePathEntryKind.INNER_TYPE); 941 } 942 throw new RuntimeException(); 943 944 case NEW_ARRAY: 945 if (d == 0) { 946 if (!r.astPath.isEmpty()) { 947 ASTPath.ASTEntry e = r.astPath.get(-1); 948 if (e.getTreeKind() == Tree.Kind.NEW_ARRAY) { 949 int a = 0; 950 while (tpe.tag == TypePathEntryKind.ARRAY) { 951 ++a; 952 if (!iter.hasNext()) { break; } 953 tpe = iter.next(); 954 } 955 r = r.replacePath(r.astPath.getParentPath()) 956 .extend(Tree.Kind.NEW_ARRAY, ASTPath.TYPE, a); 957 break; 958 } 959 } 960 r = r.extend(Tree.Kind.ARRAY_TYPE, ASTPath.TYPE); 961 t = ((JCTree.JCArrayTypeTree) t).getType(); 962 break; 963 } 964 throw new RuntimeException(); 965 966 case PARAMETERIZED_TYPE: 967 if (d == 0 && tpe.tag == TypePathEntryKind.TYPE_ARGUMENT) { 968 r = r.extend(Tree.Kind.PARAMETERIZED_TYPE, 969 ASTPath.TYPE_ARGUMENT, tpe.arg); 970 t = ((JCTree.JCTypeApply) t).getTypeArguments().get(tpe.arg); 971 break; 972 } else if (d > 0 && tpe.tag == TypePathEntryKind.INNER_TYPE) { 973 Tree temp = ((JCTree.JCTypeApply) t).getType(); 974 r = r.extend(Tree.Kind.PARAMETERIZED_TYPE, ASTPath.TYPE); 975 t = temp; 976 do { 977 temp = ((JCTree.JCFieldAccess) temp).getExpression(); 978 if (!iter.hasNext()) { 979 do { 980 r = r.extend(Tree.Kind.MEMBER_SELECT, ASTPath.EXPRESSION); 981 } while (--d > 0); 982 return r; 983 } 984 tpe = iter.next(); 985 if (--d == 0) { 986 continue outer; // avoid next() at end of loop 987 } 988 } while (tpe.tag == TypePathEntryKind.INNER_TYPE); 989 } 990 throw new RuntimeException(); 991 992 case EXTENDS_WILDCARD: 993 case SUPER_WILDCARD: 994 case UNBOUNDED_WILDCARD: 995 if (tpe.tag == TypePathEntryKind.WILDCARD) { 996 t = ((JCTree.JCWildcard) t).getBound(); 997 break; 998 } 999 throw new RuntimeException(); 1000 1001 default: 1002 if (iter.hasNext()) { 1003 throw new RuntimeException(); 1004 } 1005 } 1006 1007 if (!iter.hasNext()) { return r; } 1008 tpe = iter.next(); 1009 } 1010 } 1011 1012 // merge annotations, assuming types are structurally identical 1013 private void mergeTypedInsertions(TypedInsertion ins0, TypedInsertion ins1) { 1014 mergeTypes(ins0.getType(), ins1.getType()); 1015 } 1016 1017 private void mergeTypes(Type t0, Type t1) { 1018 if (t0 == t1) { return; } 1019 switch (t0.getKind()) { 1020 case ARRAY: 1021 { 1022 ArrayType at0 = (ArrayType) t0; 1023 ArrayType at1 = (ArrayType) t1; 1024 mergeTypes(at0.getComponentType(), at1.getComponentType()); 1025 return; 1026 } 1027 case BOUNDED: 1028 { 1029 BoundedType bt0 = (BoundedType) t0; 1030 BoundedType bt1 = (BoundedType) t1; 1031 if (bt0.getBoundKind() != bt1.getBoundKind()) { break; } 1032 mergeTypes(bt0.getBound(), bt1.getBound()); 1033 mergeTypes(bt0.getName(), bt1.getName()); 1034 return; 1035 } 1036 case DECLARED: 1037 { 1038 DeclaredType dt0 = (DeclaredType) t0; 1039 DeclaredType dt1 = (DeclaredType) t1; 1040 List<Type> tps0 = dt0.getTypeParameters(); 1041 List<Type> tps1 = dt1.getTypeParameters(); 1042 int n = tps0.size(); 1043 if (tps1.size() != n) { break; } 1044 mergeTypes(dt0.getInnerType(), dt1.getInnerType()); 1045 for (String anno : dt1.getAnnotations()) { 1046 if (!dt0.getAnnotations().contains(anno)) { 1047 dt0.addAnnotation(anno); 1048 } 1049 } 1050 for (int i = 0; i < n; i++) { 1051 mergeTypes(tps0.get(i), tps1.get(i)); 1052 } 1053 return; 1054 } 1055 } 1056 throw new RuntimeException(); 1057 } 1058 1059 // Returns the depth of the innermost local type of a type AST. 1060 private int localDepth(Tree node) { 1061 Tree t = node; 1062 int n = 0; 1063loop: 1064 while (t != null) { 1065 switch (t.getKind()) { 1066 case ANNOTATED_TYPE: 1067 t = ((AnnotatedTypeTree) t).getUnderlyingType(); 1068 break; 1069 case MEMBER_SELECT: 1070 if (t instanceof JCTree.JCFieldAccess) { 1071 JCTree.JCFieldAccess jfa = (JCTree.JCFieldAccess) t; 1072 if (jfa.sym.kind == Kinds.PCK) { 1073 t = jfa.getExpression(); 1074 continue; 1075 } 1076 } 1077 t = ((MemberSelectTree) t).getExpression(); 1078 ++n; 1079 break; 1080 default: 1081 break loop; 1082 } 1083 } 1084 return n; 1085 } 1086 1087 // Provides an additional level of indexing. 1088 class ASTRecordMap<E> implements Map<ASTRecord, E> { 1089 Map<ASTRecord, SortedMap<ASTPath, E>> back; 1090 1091 ASTRecordMap() { 1092 back = new HashMap<ASTRecord, SortedMap<ASTPath, E>>(); 1093 } 1094 1095 private SortedMap<ASTPath, E> getMap(ASTRecord rec) { 1096 ASTRecord key = rec.replacePath(ASTPath.empty()); 1097 SortedMap<ASTPath, E> map = back.get(key); 1098 if (map == null) { 1099 map = new TreeMap<ASTPath, E>(); 1100 back.put(key, map); 1101 } 1102 return map; 1103 } 1104 1105 @Override 1106 public int size() { 1107 int n = 0; 1108 for (SortedMap<ASTPath, E> map : back.values()) { 1109 n += map.size(); 1110 } 1111 return n; 1112 } 1113 1114 @Override 1115 public boolean isEmpty() { 1116 return size() == 0; 1117 } 1118 1119 @Override 1120 public boolean containsKey(Object key) { 1121 ASTRecord rec = (ASTRecord) key; 1122 SortedMap<ASTPath, E> m = getMap(rec); 1123 return m != null && m.containsKey(rec.astPath); 1124 } 1125 1126 @Override 1127 public boolean containsValue(Object value) { 1128 @SuppressWarnings("unchecked") 1129 E e = (E) value; 1130 for (SortedMap<ASTPath, E> map : back.values()) { 1131 if (map.containsValue(e)) { return true; } 1132 } 1133 return false; 1134 } 1135 1136 @Override 1137 public E get(Object key) { 1138 ASTRecord rec = (ASTRecord) key; 1139 SortedMap<ASTPath, E> map = getMap(rec); 1140 return map == null ? null : map.get(rec.astPath); 1141 } 1142 1143 @Override 1144 public E put(ASTRecord key, E value) { 1145 ASTRecord rec = key; 1146 SortedMap<ASTPath, E> map = getMap(rec); 1147 return map == null ? null : map.put(rec.astPath, value); 1148 } 1149 1150 @Override 1151 public E remove(Object key) { 1152 ASTRecord rec = (ASTRecord) key; 1153 SortedMap<ASTPath, E> map = getMap(rec); 1154 return map == null ? null : map.remove(rec.astPath); 1155 } 1156 1157 @Override 1158 public void putAll(Map<? extends ASTRecord, ? extends E> m) { 1159 for (Map.Entry<? extends ASTRecord, ? extends E> entry : m.entrySet()) { 1160 put(entry.getKey(), entry.getValue()); 1161 } 1162 } 1163 1164 @Override 1165 public void clear() { 1166 back.clear(); 1167 } 1168 1169 @Override 1170 public Set<ASTRecord> keySet() { 1171 return back.keySet(); 1172 } 1173 1174 @Override 1175 public Collection<E> values() { 1176 Set<E> ret = new LinkedHashSet<E>(); 1177 for (SortedMap<ASTPath, E> m : back.values()) { 1178 ret.addAll(m.values()); 1179 } 1180 return ret; 1181 } 1182 1183 @Override 1184 public Set<Map.Entry<ASTRecord, E>> entrySet() { 1185 final int size = size(); 1186 return new AbstractSet<Map.Entry<ASTRecord, E>>() { 1187 @Override 1188 public Iterator<Map.Entry<ASTRecord, E>> iterator() { 1189 return new Iterator<Map.Entry<ASTRecord, E>>() { 1190 Iterator<Map.Entry<ASTRecord, SortedMap<ASTPath, E>>> iter0 = 1191 back.entrySet().iterator(); 1192 Iterator<Map.Entry<ASTPath, E>> iter1 = 1193 Collections.<Map.Entry<ASTPath, E>>emptyIterator(); 1194 ASTRecord rec = null; 1195 1196 @Override 1197 public boolean hasNext() { 1198 if (iter1.hasNext()) { return true; } 1199 while (iter0.hasNext()) { 1200 Map.Entry<ASTRecord, SortedMap<ASTPath, E>> entry = 1201 iter0.next(); 1202 rec = entry.getKey(); 1203 iter1 = entry.getValue().entrySet().iterator(); 1204 if (iter1.hasNext()) { return true; } 1205 } 1206 iter1 = Collections.<Map.Entry<ASTPath, E>>emptyIterator(); 1207 return false; 1208 } 1209 1210 @Override 1211 public Map.Entry<ASTRecord, E> next() { 1212 if (!hasNext()) { throw new NoSuchElementException(); } 1213 final Map.Entry<ASTPath, E> e0 = iter1.next(); 1214 return new Map.Entry<ASTRecord, E>() { 1215 final ASTRecord key = rec.replacePath(e0.getKey()); 1216 final E val = e0.getValue(); 1217 @Override public ASTRecord getKey() { return key; } 1218 @Override public E getValue() { return val; } 1219 @Override public E setValue(E value) { 1220 throw new UnsupportedOperationException(); 1221 } 1222 }; 1223 } 1224 1225 @Override 1226 public void remove() { 1227 throw new UnsupportedOperationException(); 1228 } 1229 }; 1230 } 1231 1232 @Override 1233 public int size() { return size; } 1234 }; 1235 } 1236 } 1237 1238 // Simple AST implementation used only in determining type paths. 1239 static abstract class TypeTree implements ExpressionTree { 1240 private static Map<String, TypeTag> primTags = 1241 new HashMap<String, TypeTag>(); 1242 { 1243 primTags.put("byte", TypeTag.BYTE); 1244 primTags.put("char", TypeTag.CHAR); 1245 primTags.put("short", TypeTag.SHORT); 1246 primTags.put("long", TypeTag.LONG); 1247 primTags.put("float", TypeTag.FLOAT); 1248 primTags.put("int", TypeTag.INT); 1249 primTags.put("double", TypeTag.DOUBLE); 1250 primTags.put("boolean", TypeTag.BOOLEAN); 1251 } 1252 1253 static TypeTree fromJCTree(JCTree jt) { 1254 if (jt != null) { 1255 Kind kind = jt.getKind(); 1256 switch (kind) { 1257 case ANNOTATED_TYPE: 1258 return fromJCTree( 1259 ((JCTree.JCAnnotatedType) jt).getUnderlyingType()); 1260 case IDENTIFIER: 1261 return new IdenT( 1262 ((JCTree.JCIdent) jt).sym.getSimpleName().toString()); 1263 case ARRAY_TYPE: 1264 return new ArrT( 1265 fromJCTree(((JCTree.JCArrayTypeTree) jt).getType())); 1266 case MEMBER_SELECT: 1267 return new LocT( 1268 fromJCTree(((JCTree.JCFieldAccess) jt).getExpression()), 1269 ((JCTree.JCFieldAccess) jt).getIdentifier()); 1270 case EXTENDS_WILDCARD: 1271 case SUPER_WILDCARD: 1272 return new WildT(kind, 1273 fromJCTree(((JCTree.JCWildcard) jt).getBound())); 1274 case UNBOUNDED_WILDCARD: 1275 return new WildT(); 1276 case PARAMETERIZED_TYPE: 1277 com.sun.tools.javac.util.List<JCExpression> typeArgs = 1278 ((JCTree.JCTypeApply) jt).getTypeArguments(); 1279 List<Tree> args = new ArrayList<Tree>(typeArgs.size()); 1280 for (JCTree.JCExpression typeArg : typeArgs) { 1281 args.add(fromJCTree(typeArg)); 1282 } 1283 return new ParT( 1284 fromJCTree(((JCTree.JCTypeApply) jt).getType()), 1285 args); 1286 default: 1287 break; 1288 } 1289 } 1290 return null; 1291 } 1292 1293 static TypeTree fromType(final Type type) { 1294 switch (type.getKind()) { 1295 case ARRAY: 1296 final ArrayType atype = (ArrayType) type; 1297 final TypeTree componentType = fromType(atype.getComponentType()); 1298 return new ArrT(componentType); 1299 case BOUNDED: 1300 final BoundedType btype = (BoundedType) type; 1301 final BoundedType.BoundKind bk = btype.getBoundKind(); 1302 final String bname = btype.getName().getName(); 1303 final TypeTree bound = fromType(btype.getBound()); 1304 return new Param(bname, bk, bound); 1305 case DECLARED: 1306 final DeclaredType dtype = (DeclaredType) type; 1307 if (dtype.isWildcard()) { 1308 return new WildT(); 1309 } else { 1310 final String dname = dtype.getName(); 1311 TypeTag typeTag = primTags.get(dname); 1312 if (typeTag == null) { 1313 final TypeTree base = new IdenT(dname); 1314 TypeTree ret = base; 1315 List<Type> params = dtype.getTypeParameters(); 1316 DeclaredType inner = dtype.getInnerType(); 1317 if (!params.isEmpty()) { 1318 final List<Tree> typeArgs = new ArrayList<Tree>(params.size()); 1319 for (Type t : params) { typeArgs.add(fromType(t)); } 1320 ret = new ParT(base, typeArgs); 1321 } 1322 return inner == null ? ret : meld(fromType(inner), ret); 1323 } else { 1324 final TypeKind typeKind = typeTag.getPrimitiveTypeKind(); 1325 return new PrimT(typeKind); 1326 } 1327 } 1328 default: 1329 throw new RuntimeException("unknown type kind " + type.getKind()); 1330 } 1331 } 1332 1333 static TypeTree fromType(final com.sun.tools.javac.code.Type type) { 1334 return fromType(conv(type)); 1335 } 1336 1337 /** 1338 * @param jtype 1339 * @return 1340 */ 1341 static Type conv(final com.sun.tools.javac.code.Type jtype) { 1342 Type type = null; 1343 DeclaredType d; 1344 com.sun.tools.javac.code.Type t; 1345 switch (jtype.getKind()) { 1346 case ARRAY: 1347 t = ((com.sun.tools.javac.code.Type.ArrayType) jtype).elemtype; 1348 type = new ArrayType(conv(t)); 1349 break; 1350 case DECLARED: 1351 t = jtype; 1352 d = null; 1353 do { 1354 DeclaredType d0 = d; 1355 com.sun.tools.javac.code.Type.ClassType ct = 1356 (com.sun.tools.javac.code.Type.ClassType) t; 1357 d = new DeclaredType(ct.tsym.name.toString()); 1358 d.setInnerType(d0); 1359 d0 = d; 1360 for (com.sun.tools.javac.code.Type a : ct.getTypeArguments()) { 1361 d.addTypeParameter(conv(a)); 1362 } 1363 t = ct.getEnclosingType(); 1364 } while (t.getKind() == TypeKind.DECLARED); 1365 type = d; 1366 break; 1367 case WILDCARD: 1368 BoundedType.BoundKind k; 1369 t = ((com.sun.tools.javac.code.Type.WildcardType) jtype).bound; 1370 switch (((com.sun.tools.javac.code.Type.WildcardType) jtype).kind) { 1371 case EXTENDS: 1372 k = BoundedType.BoundKind.EXTENDS; 1373 break; 1374 case SUPER: 1375 k = BoundedType.BoundKind.SUPER; 1376 break; 1377 case UNBOUND: 1378 k = null; 1379 type = new DeclaredType("?"); 1380 break; 1381 default: 1382 throw new RuntimeException(); 1383 } 1384 if (k != null) { 1385 d = new DeclaredType(jtype.tsym.name.toString()); 1386 type = new BoundedType(d, k, (DeclaredType) conv(t)); 1387 } 1388 break; 1389 case TYPEVAR: 1390 t = ((com.sun.tools.javac.code.Type.TypeVar) jtype).getUpperBound(); 1391 type = conv(t); 1392 if (type.getKind() == Type.Kind.DECLARED) { 1393 type = new BoundedType(new DeclaredType(jtype.tsym.name.toString()), 1394 BoundedType.BoundKind.EXTENDS, (DeclaredType) type); 1395 } // otherwise previous conv should have been here already 1396 break; 1397 case INTERSECTION: 1398 t = jtype.tsym.erasure_field; // ??? 1399 type = new DeclaredType(t.tsym.name.toString()); 1400 break; 1401 case UNION: 1402 // TODO 1403 break; 1404 case BOOLEAN: 1405 case BYTE: 1406 case CHAR: 1407 case DOUBLE: 1408 case LONG: 1409 case SHORT: 1410 case FLOAT: 1411 case INT: 1412 type = new DeclaredType(jtype.tsym.name.toString()); 1413 break; 1414 // case ERROR: 1415 // case EXECUTABLE: 1416 // case NONE: 1417 // case NULL: 1418 // case OTHER: 1419 // case PACKAGE: 1420 // case VOID: 1421 default: 1422 break; 1423 } 1424 return type; 1425 } 1426 1427 private static TypeTree meld(final TypeTree t0, final TypeTree t1) { 1428 switch (t0.getKind()) { 1429 case IDENTIFIER: 1430 IdenT it = (IdenT) t0; 1431 return new LocT(t1, it.getName()); 1432 case MEMBER_SELECT: 1433 LocT lt = (LocT) t0; 1434 return new LocT(meld(lt.getExpression(), t1), lt.getIdentifier()); 1435 case PARAMETERIZED_TYPE: 1436 ParT pt = (ParT) t0; 1437 return new ParT(meld(pt.getType(), t1), pt.getTypeArguments()); 1438 default: 1439 throw new IllegalArgumentException("unexpected type " + t0); 1440 } 1441 } 1442 1443 static final class ArrT extends TypeTree implements ArrayTypeTree { 1444 private final TypeTree componentType; 1445 1446 ArrT(TypeTree componentType) { 1447 this.componentType = componentType; 1448 } 1449 1450 @Override 1451 public Kind getKind() { return Kind.ARRAY_TYPE; } 1452 1453 @Override 1454 public <R, D> R accept(TreeVisitor<R, D> visitor, D data) { 1455 return visitor.visitArrayType(this, data); 1456 } 1457 1458 @Override 1459 public TypeTree getType() { return componentType; } 1460 1461 @Override 1462 public String toString() { return componentType + "[]"; } 1463 } 1464 1465 static final class LocT extends TypeTree implements MemberSelectTree { 1466 private final TypeTree expr; 1467 private final Name name; 1468 1469 LocT(TypeTree expr, Name name) { 1470 this.expr = expr; 1471 this.name = name; 1472 } 1473 1474 @Override 1475 public Kind getKind() { return Kind.MEMBER_SELECT; } 1476 1477 @Override 1478 public <R, D> R accept(TreeVisitor<R, D> visitor, D data) { 1479 return visitor.visitMemberSelect(this, data); 1480 } 1481 1482 @Override 1483 public TypeTree getExpression() { return expr; } 1484 1485 @Override 1486 public Name getIdentifier() { return name; } 1487 1488 @Override 1489 public String toString() { return expr + "." + name; } 1490 } 1491 1492 static final class ParT extends TypeTree implements ParameterizedTypeTree { 1493 private final TypeTree base; 1494 private final List<? extends Tree> typeArgs; 1495 1496 ParT(TypeTree base, List<? extends Tree> typeArgs) { 1497 this.base = base; 1498 this.typeArgs = typeArgs; 1499 } 1500 1501 @Override 1502 public Kind getKind() { return Kind.PARAMETERIZED_TYPE; } 1503 1504 @Override 1505 public <R, D> R accept(TreeVisitor<R, D> visitor, D data) { 1506 return visitor.visitParameterizedType(this, data); 1507 } 1508 1509 @Override 1510 public TypeTree getType() { return base; } 1511 1512 @Override 1513 public List<? extends Tree> getTypeArguments() { 1514 return typeArgs; 1515 } 1516 1517 @Override 1518 public String toString() { 1519 StringBuilder sb = new StringBuilder(base.toString()); 1520 String s = "<"; 1521 for (Tree t : typeArgs) { 1522 sb.append(s); 1523 sb.append(t.toString()); 1524 s = ", "; 1525 } 1526 sb.append('>'); 1527 return sb.toString(); 1528 } 1529 } 1530 1531 static final class PrimT extends TypeTree implements PrimitiveTypeTree { 1532 private final TypeKind typeKind; 1533 1534 PrimT(TypeKind typeKind) { 1535 this.typeKind = typeKind; 1536 } 1537 1538 @Override 1539 public Kind getKind() { return Kind.PRIMITIVE_TYPE; } 1540 1541 @Override 1542 public <R, D> R accept(TreeVisitor<R, D> visitor, D data) { 1543 return visitor.visitPrimitiveType(this, data); 1544 } 1545 1546 @Override 1547 public TypeKind getPrimitiveTypeKind() { return typeKind; } 1548 1549 @Override 1550 public String toString() { 1551 switch (typeKind) { 1552 case BOOLEAN: return "boolean"; 1553 case BYTE: return "byte"; 1554 case CHAR: return "char"; 1555 case DOUBLE: return "double"; 1556 case FLOAT: return "float"; 1557 case INT: return "int"; 1558 case LONG: return "long"; 1559 case SHORT: return "short"; 1560 // case VOID: return "void"; 1561 // case WILDCARD: return "?"; 1562 default: 1563 throw new IllegalArgumentException("unexpected type kind " 1564 + typeKind); 1565 } 1566 } 1567 } 1568 1569 static final class IdenT extends TypeTree implements IdentifierTree { 1570 private final String name; 1571 1572 IdenT(String dname) { 1573 this.name = dname; 1574 } 1575 1576 @Override 1577 public Kind getKind() { return Kind.IDENTIFIER; } 1578 1579 @Override 1580 public <R, D> R accept(TreeVisitor<R, D> visitor, D data) { 1581 return visitor.visitIdentifier(this, data); 1582 } 1583 1584 @Override 1585 public Name getName() { return new TypeName(name); } 1586 1587 @Override 1588 public String toString() { return name; } 1589 } 1590 1591 static final class WildT extends TypeTree implements WildcardTree { 1592 private final TypeTree bound; 1593 private final Kind kind; 1594 1595 WildT() { 1596 this(Kind.UNBOUNDED_WILDCARD, null); 1597 } 1598 1599 WildT(TypeTree bound, BoundedType.BoundKind bk) { 1600 this(bk == BoundedType.BoundKind.SUPER 1601 ? Kind.SUPER_WILDCARD 1602 : Kind.EXTENDS_WILDCARD, 1603 bound); 1604 } 1605 1606 WildT(Kind kind, TypeTree bound) { 1607 this.kind = kind; 1608 this.bound = bound; 1609 } 1610 1611 @Override 1612 public Kind getKind() { return kind; } 1613 1614 @Override 1615 public <R, D> R accept(TreeVisitor<R, D> visitor, D data) { 1616 return visitor.visitWildcard(this, data); 1617 } 1618 1619 @Override 1620 public Tree getBound() { return bound; } 1621 1622 @Override 1623 public String toString() { return "?"; } 1624 } 1625 1626 static final class Param extends TypeTree implements TypeParameterTree { 1627 private final String bname; 1628 private final BoundedType.BoundKind bk; 1629 private final Tree bound; 1630 1631 Param(String bname, BoundedType.BoundKind bk, TypeTree bound) { 1632 this.bname = bname; 1633 this.bk = bk; 1634 this.bound = bound; 1635 } 1636 1637 @Override 1638 public Kind getKind() { return Kind.TYPE_PARAMETER; } 1639 1640 @Override 1641 public <R, D> R accept(TreeVisitor<R, D> visitor, D data) { 1642 return visitor.visitTypeParameter(this, data); 1643 } 1644 1645 @Override 1646 public Name getName() { return new TypeName(bname); } 1647 1648 @Override 1649 public List<? extends Tree> getBounds() { 1650 return Collections.singletonList(bound); 1651 } 1652 1653 @Override 1654 public List<? extends AnnotationTree> getAnnotations() { 1655 return Collections.emptyList(); 1656 } 1657 1658 @Override 1659 public String toString() { 1660 return bname + " " + bk.toString() + " " + bound.toString(); 1661 } 1662 } 1663 1664 static final class TypeName implements Name { 1665 private final String str; 1666 1667 TypeName(String str) { 1668 this.str = str; 1669 } 1670 1671 @Override 1672 public int length() { return str.length(); } 1673 1674 @Override 1675 public char charAt(int index) { return str.charAt(index); } 1676 1677 @Override 1678 public CharSequence subSequence(int start, int end) { 1679 return str.subSequence(start, end); 1680 } 1681 1682 @Override 1683 public boolean contentEquals(CharSequence cs) { 1684 if (cs != null) { 1685 int n = length(); 1686 if (cs.length() == n) { 1687 for (int i = 0; i < n; i++) { 1688 if (charAt(i) != cs.charAt(i)) { return false; } 1689 } 1690 return true; 1691 } 1692 } 1693 return false; 1694 } 1695 1696 @Override 1697 public String toString() { return str; } 1698 } 1699 } 1700} 1701