2393 signatureBuffer = new byte[ns]; |
2325 signatureBuffer = new byte[ns]; |
2394 } |
2326 } |
2395 readClass(c); |
2327 readClass(c); |
2396 } |
2328 } |
2397 |
2329 |
2398 /************************************************************************ |
2330 public void readClassFile(ClassSymbol c) { |
2399 * Adjusting flags |
|
2400 ***********************************************************************/ |
|
2401 |
|
2402 long adjustFieldFlags(long flags) { |
|
2403 return flags; |
|
2404 } |
|
2405 long adjustMethodFlags(long flags) { |
|
2406 if ((flags & ACC_BRIDGE) != 0) { |
|
2407 flags &= ~ACC_BRIDGE; |
|
2408 flags |= BRIDGE; |
|
2409 if (!allowGenerics) |
|
2410 flags &= ~SYNTHETIC; |
|
2411 } |
|
2412 if ((flags & ACC_VARARGS) != 0) { |
|
2413 flags &= ~ACC_VARARGS; |
|
2414 flags |= VARARGS; |
|
2415 } |
|
2416 return flags; |
|
2417 } |
|
2418 long adjustClassFlags(long flags) { |
|
2419 return flags & ~ACC_SUPER; // SUPER and SYNCHRONIZED bits overloaded |
|
2420 } |
|
2421 |
|
2422 /************************************************************************ |
|
2423 * Loading Classes |
|
2424 ***********************************************************************/ |
|
2425 |
|
2426 /** Completion for classes to be loaded. Before a class is loaded |
|
2427 * we make sure its enclosing class (if any) is loaded. |
|
2428 */ |
|
2429 private void complete(Symbol sym) throws CompletionFailure { |
|
2430 if (sym.kind == TYP) { |
|
2431 ClassSymbol c = (ClassSymbol)sym; |
|
2432 c.members_field = new Scope.ErrorScope(c); // make sure it's always defined |
|
2433 annotate.enterStart(); |
|
2434 try { |
|
2435 completeOwners(c.owner); |
|
2436 completeEnclosing(c); |
|
2437 } finally { |
|
2438 // The flush needs to happen only after annotations |
|
2439 // are filled in. |
|
2440 annotate.enterDoneWithoutFlush(); |
|
2441 } |
|
2442 fillIn(c); |
|
2443 } else if (sym.kind == PCK) { |
|
2444 PackageSymbol p = (PackageSymbol)sym; |
|
2445 try { |
|
2446 fillIn(p); |
|
2447 } catch (IOException ex) { |
|
2448 throw new CompletionFailure(sym, ex.getLocalizedMessage()).initCause(ex); |
|
2449 } |
|
2450 } |
|
2451 if (!filling) |
|
2452 annotate.flush(); // finish attaching annotations |
|
2453 } |
|
2454 |
|
2455 /** complete up through the enclosing package. */ |
|
2456 private void completeOwners(Symbol o) { |
|
2457 if (o.kind != PCK) completeOwners(o.owner); |
|
2458 o.complete(); |
|
2459 } |
|
2460 |
|
2461 /** |
|
2462 * Tries to complete lexically enclosing classes if c looks like a |
|
2463 * nested class. This is similar to completeOwners but handles |
|
2464 * the situation when a nested class is accessed directly as it is |
|
2465 * possible with the Tree API or javax.lang.model.*. |
|
2466 */ |
|
2467 private void completeEnclosing(ClassSymbol c) { |
|
2468 if (c.owner.kind == PCK) { |
|
2469 Symbol owner = c.owner; |
|
2470 for (Name name : Convert.enclosingCandidates(Convert.shortName(c.name))) { |
|
2471 Symbol encl = owner.members().lookup(name).sym; |
|
2472 if (encl == null) |
|
2473 encl = syms.classes.get(TypeSymbol.formFlatName(name, owner)); |
|
2474 if (encl != null) |
|
2475 encl.complete(); |
|
2476 } |
|
2477 } |
|
2478 } |
|
2479 |
|
2480 /** We can only read a single class file at a time; this |
|
2481 * flag keeps track of when we are currently reading a class |
|
2482 * file. |
|
2483 */ |
|
2484 private boolean filling = false; |
|
2485 |
|
2486 /** Fill in definition of class `c' from corresponding class or |
|
2487 * source file. |
|
2488 */ |
|
2489 private void fillIn(ClassSymbol c) { |
|
2490 if (completionFailureName == c.fullname) { |
|
2491 throw new CompletionFailure(c, "user-selected completion failure by class name"); |
|
2492 } |
|
2493 currentOwner = c; |
2331 currentOwner = c; |
|
2332 currentClassFile = c.classfile; |
2494 warnedAttrs.clear(); |
2333 warnedAttrs.clear(); |
2495 JavaFileObject classfile = c.classfile; |
2334 filling = true; |
2496 if (classfile != null) { |
2335 try { |
2497 JavaFileObject previousClassFile = currentClassFile; |
2336 bp = 0; |
2498 try { |
2337 buf = readInputStream(buf, c.classfile.openInputStream()); |
2499 if (filling) { |
2338 readClassBuffer(c); |
2500 Assert.error("Filling " + classfile.toUri() + " during " + previousClassFile); |
2339 if (!missingTypeVariables.isEmpty() && !foundTypeVariables.isEmpty()) { |
2501 } |
2340 List<Type> missing = missingTypeVariables; |
2502 currentClassFile = classfile; |
2341 List<Type> found = foundTypeVariables; |
2503 if (verbose) { |
2342 missingTypeVariables = List.nil(); |
2504 log.printVerbose("loading", currentClassFile.toString()); |
2343 foundTypeVariables = List.nil(); |
2505 } |
2344 filling = false; |
2506 if (classfile.getKind() == JavaFileObject.Kind.CLASS) { |
2345 ClassType ct = (ClassType)currentOwner.type; |
2507 filling = true; |
2346 ct.supertype_field = |
2508 try { |
2347 types.subst(ct.supertype_field, missing, found); |
2509 bp = 0; |
2348 ct.interfaces_field = |
2510 buf = readInputStream(buf, classfile.openInputStream()); |
2349 types.subst(ct.interfaces_field, missing, found); |
2511 readClassFile(c); |
2350 } else if (missingTypeVariables.isEmpty() != |
2512 if (!missingTypeVariables.isEmpty() && !foundTypeVariables.isEmpty()) { |
2351 foundTypeVariables.isEmpty()) { |
2513 List<Type> missing = missingTypeVariables; |
2352 Name name = missingTypeVariables.head.tsym.name; |
2514 List<Type> found = foundTypeVariables; |
2353 throw badClassFile("undecl.type.var", name); |
2515 missingTypeVariables = List.nil(); |
2354 } |
2516 foundTypeVariables = List.nil(); |
2355 } catch (IOException ex) { |
2517 filling = false; |
2356 throw badClassFile("unable.to.access.file", ex.getMessage()); |
2518 ClassType ct = (ClassType)currentOwner.type; |
2357 } catch (ArrayIndexOutOfBoundsException ex) { |
2519 ct.supertype_field = |
2358 throw badClassFile("bad.class.file", c.flatname); |
2520 types.subst(ct.supertype_field, missing, found); |
2359 } finally { |
2521 ct.interfaces_field = |
2360 missingTypeVariables = List.nil(); |
2522 types.subst(ct.interfaces_field, missing, found); |
2361 foundTypeVariables = List.nil(); |
2523 } else if (missingTypeVariables.isEmpty() != |
2362 filling = false; |
2524 foundTypeVariables.isEmpty()) { |
|
2525 Name name = missingTypeVariables.head.tsym.name; |
|
2526 throw badClassFile("undecl.type.var", name); |
|
2527 } |
|
2528 } finally { |
|
2529 missingTypeVariables = List.nil(); |
|
2530 foundTypeVariables = List.nil(); |
|
2531 filling = false; |
|
2532 } |
|
2533 } else { |
|
2534 if (sourceCompleter != null) { |
|
2535 sourceCompleter.complete(c); |
|
2536 } else { |
|
2537 throw new IllegalStateException("Source completer required to read " |
|
2538 + classfile.toUri()); |
|
2539 } |
|
2540 } |
|
2541 return; |
|
2542 } catch (IOException ex) { |
|
2543 throw badClassFile("unable.to.access.file", ex.getMessage()); |
|
2544 } catch (ArrayIndexOutOfBoundsException ex) { |
|
2545 throw badClassFile("bad.class.file", c.flatname); |
|
2546 } finally { |
|
2547 currentClassFile = previousClassFile; |
|
2548 } |
|
2549 } else { |
|
2550 JCDiagnostic diag = |
|
2551 diagFactory.fragment("class.file.not.found", c.flatname); |
|
2552 throw |
|
2553 newCompletionFailure(c, diag); |
|
2554 } |
2363 } |
2555 } |
2364 } |
2556 // where |
2365 // where |
2557 private static byte[] readInputStream(byte[] buf, InputStream s) throws IOException { |
2366 private static byte[] readInputStream(byte[] buf, InputStream s) throws IOException { |
2558 try { |
2367 try { |
2588 buf = new byte[Integer.highestOneBit(needed) << 1]; |
2397 buf = new byte[Integer.highestOneBit(needed) << 1]; |
2589 System.arraycopy(old, 0, buf, 0, old.length); |
2398 System.arraycopy(old, 0, buf, 0, old.length); |
2590 } |
2399 } |
2591 return buf; |
2400 return buf; |
2592 } |
2401 } |
2593 /** Static factory for CompletionFailure objects. |
2402 |
2594 * In practice, only one can be used at a time, so we share one |
2403 /** We can only read a single class file at a time; this |
2595 * to reduce the expense of allocating new exception objects. |
2404 * flag keeps track of when we are currently reading a class |
2596 */ |
2405 * file. |
2597 private CompletionFailure newCompletionFailure(TypeSymbol c, |
2406 */ |
2598 JCDiagnostic diag) { |
2407 public boolean filling = false; |
2599 if (!cacheCompletionFailure) { |
|
2600 // log.warning("proc.messager", |
|
2601 // Log.getLocalizedString("class.file.not.found", c.flatname)); |
|
2602 // c.debug.printStackTrace(); |
|
2603 return new CompletionFailure(c, diag); |
|
2604 } else { |
|
2605 CompletionFailure result = cachedCompletionFailure; |
|
2606 result.sym = c; |
|
2607 result.diag = diag; |
|
2608 return result; |
|
2609 } |
|
2610 } |
|
2611 private CompletionFailure cachedCompletionFailure = |
|
2612 new CompletionFailure(null, (JCDiagnostic) null); |
|
2613 { |
|
2614 cachedCompletionFailure.setStackTrace(new StackTraceElement[0]); |
|
2615 } |
|
2616 |
|
2617 |
|
2618 /** Load a toplevel class with given fully qualified name |
|
2619 * The class is entered into `classes' only if load was successful. |
|
2620 */ |
|
2621 public ClassSymbol loadClass(Name flatname) throws CompletionFailure { |
|
2622 boolean absent = syms.classes.get(flatname) == null; |
|
2623 ClassSymbol c = syms.enterClass(flatname); |
|
2624 if (c.members_field == null && c.completer != null) { |
|
2625 try { |
|
2626 c.complete(); |
|
2627 } catch (CompletionFailure ex) { |
|
2628 if (absent) syms.classes.remove(flatname); |
|
2629 throw ex; |
|
2630 } |
|
2631 } |
|
2632 return c; |
|
2633 } |
|
2634 |
2408 |
2635 /************************************************************************ |
2409 /************************************************************************ |
2636 * Loading Packages |
2410 * Adjusting flags |
2637 ***********************************************************************/ |
2411 ***********************************************************************/ |
2638 |
2412 |
2639 /** Include class corresponding to given class file in package, |
2413 long adjustFieldFlags(long flags) { |
2640 * unless (1) we already have one the same kind (.class or .java), or |
2414 return flags; |
2641 * (2) we have one of the other kind, and the given class file |
2415 } |
2642 * is older. |
2416 |
2643 */ |
2417 long adjustMethodFlags(long flags) { |
2644 protected void includeClassFile(PackageSymbol p, JavaFileObject file) { |
2418 if ((flags & ACC_BRIDGE) != 0) { |
2645 if ((p.flags_field & EXISTS) == 0) |
2419 flags &= ~ACC_BRIDGE; |
2646 for (Symbol q = p; q != null && q.kind == PCK; q = q.owner) |
2420 flags |= BRIDGE; |
2647 q.flags_field |= EXISTS; |
2421 if (!allowGenerics) |
2648 JavaFileObject.Kind kind = file.getKind(); |
2422 flags &= ~SYNTHETIC; |
2649 int seen; |
2423 } |
2650 if (kind == JavaFileObject.Kind.CLASS) |
2424 if ((flags & ACC_VARARGS) != 0) { |
2651 seen = CLASS_SEEN; |
2425 flags &= ~ACC_VARARGS; |
2652 else |
2426 flags |= VARARGS; |
2653 seen = SOURCE_SEEN; |
2427 } |
2654 String binaryName = fileManager.inferBinaryName(currentLoc, file); |
2428 return flags; |
2655 int lastDot = binaryName.lastIndexOf("."); |
2429 } |
2656 Name classname = names.fromString(binaryName.substring(lastDot + 1)); |
2430 |
2657 boolean isPkgInfo = classname == names.package_info; |
2431 long adjustClassFlags(long flags) { |
2658 ClassSymbol c = isPkgInfo |
2432 return flags & ~ACC_SUPER; // SUPER and SYNCHRONIZED bits overloaded |
2659 ? p.package_info |
2433 } |
2660 : (ClassSymbol) p.members_field.lookup(classname).sym; |
|
2661 if (c == null) { |
|
2662 c = syms.enterClass(classname, p); |
|
2663 if (c.classfile == null) // only update the file if's it's newly created |
|
2664 c.classfile = file; |
|
2665 if (isPkgInfo) { |
|
2666 p.package_info = c; |
|
2667 } else { |
|
2668 if (c.owner == p) // it might be an inner class |
|
2669 p.members_field.enter(c); |
|
2670 } |
|
2671 } else if (!preferCurrent && c.classfile != null && (c.flags_field & seen) == 0) { |
|
2672 // if c.classfile == null, we are currently compiling this class |
|
2673 // and no further action is necessary. |
|
2674 // if (c.flags_field & seen) != 0, we have already encountered |
|
2675 // a file of the same kind; again no further action is necessary. |
|
2676 if ((c.flags_field & (CLASS_SEEN | SOURCE_SEEN)) != 0) |
|
2677 c.classfile = preferredFileObject(file, c.classfile); |
|
2678 } |
|
2679 c.flags_field |= seen; |
|
2680 } |
|
2681 |
|
2682 /** Implement policy to choose to derive information from a source |
|
2683 * file or a class file when both are present. May be overridden |
|
2684 * by subclasses. |
|
2685 */ |
|
2686 protected JavaFileObject preferredFileObject(JavaFileObject a, |
|
2687 JavaFileObject b) { |
|
2688 |
|
2689 if (preferSource) |
|
2690 return (a.getKind() == JavaFileObject.Kind.SOURCE) ? a : b; |
|
2691 else { |
|
2692 long adate = a.getLastModified(); |
|
2693 long bdate = b.getLastModified(); |
|
2694 // 6449326: policy for bad lastModifiedTime in ClassReader |
|
2695 //assert adate >= 0 && bdate >= 0; |
|
2696 return (adate > bdate) ? a : b; |
|
2697 } |
|
2698 } |
|
2699 |
|
2700 /** |
|
2701 * specifies types of files to be read when filling in a package symbol |
|
2702 */ |
|
2703 protected EnumSet<JavaFileObject.Kind> getPackageFileKinds() { |
|
2704 return EnumSet.of(JavaFileObject.Kind.CLASS, JavaFileObject.Kind.SOURCE); |
|
2705 } |
|
2706 |
|
2707 /** |
|
2708 * this is used to support javadoc |
|
2709 */ |
|
2710 protected void extraFileActions(PackageSymbol pack, JavaFileObject fe) { |
|
2711 } |
|
2712 |
|
2713 protected Location currentLoc; // FIXME |
|
2714 |
|
2715 private boolean verbosePath = true; |
|
2716 |
|
2717 // Set to true when the currently selected file should be kept |
|
2718 private boolean preferCurrent; |
|
2719 |
|
2720 /** Load directory of package into members scope. |
|
2721 */ |
|
2722 private void fillIn(PackageSymbol p) throws IOException { |
|
2723 if (p.members_field == null) |
|
2724 p.members_field = new Scope(p); |
|
2725 |
|
2726 preferCurrent = false; |
|
2727 if (userPathsFirst) { |
|
2728 scanUserPaths(p); |
|
2729 preferCurrent = true; |
|
2730 scanPlatformPath(p); |
|
2731 } else { |
|
2732 scanPlatformPath(p); |
|
2733 scanUserPaths(p); |
|
2734 } |
|
2735 verbosePath = false; |
|
2736 } |
|
2737 |
|
2738 /** |
|
2739 * Scans class path and source path for files in given package. |
|
2740 */ |
|
2741 private void scanUserPaths(PackageSymbol p) throws IOException { |
|
2742 Set<JavaFileObject.Kind> kinds = getPackageFileKinds(); |
|
2743 |
|
2744 Set<JavaFileObject.Kind> classKinds = EnumSet.copyOf(kinds); |
|
2745 classKinds.remove(JavaFileObject.Kind.SOURCE); |
|
2746 boolean wantClassFiles = !classKinds.isEmpty(); |
|
2747 |
|
2748 Set<JavaFileObject.Kind> sourceKinds = EnumSet.copyOf(kinds); |
|
2749 sourceKinds.remove(JavaFileObject.Kind.CLASS); |
|
2750 boolean wantSourceFiles = !sourceKinds.isEmpty(); |
|
2751 |
|
2752 boolean haveSourcePath = fileManager.hasLocation(SOURCE_PATH); |
|
2753 |
|
2754 if (verbose && verbosePath) { |
|
2755 if (fileManager instanceof StandardJavaFileManager) { |
|
2756 StandardJavaFileManager fm = (StandardJavaFileManager)fileManager; |
|
2757 if (haveSourcePath && wantSourceFiles) { |
|
2758 List<File> path = List.nil(); |
|
2759 for (File file : fm.getLocation(SOURCE_PATH)) { |
|
2760 path = path.prepend(file); |
|
2761 } |
|
2762 log.printVerbose("sourcepath", path.reverse().toString()); |
|
2763 } else if (wantSourceFiles) { |
|
2764 List<File> path = List.nil(); |
|
2765 for (File file : fm.getLocation(CLASS_PATH)) { |
|
2766 path = path.prepend(file); |
|
2767 } |
|
2768 log.printVerbose("sourcepath", path.reverse().toString()); |
|
2769 } |
|
2770 if (wantClassFiles) { |
|
2771 List<File> path = List.nil(); |
|
2772 for (File file : fm.getLocation(PLATFORM_CLASS_PATH)) { |
|
2773 path = path.prepend(file); |
|
2774 } |
|
2775 for (File file : fm.getLocation(CLASS_PATH)) { |
|
2776 path = path.prepend(file); |
|
2777 } |
|
2778 log.printVerbose("classpath", path.reverse().toString()); |
|
2779 } |
|
2780 } |
|
2781 } |
|
2782 |
|
2783 String packageName = p.fullname.toString(); |
|
2784 if (wantSourceFiles && !haveSourcePath) { |
|
2785 fillIn(p, CLASS_PATH, |
|
2786 fileManager.list(CLASS_PATH, |
|
2787 packageName, |
|
2788 kinds, |
|
2789 false)); |
|
2790 } else { |
|
2791 if (wantClassFiles) |
|
2792 fillIn(p, CLASS_PATH, |
|
2793 fileManager.list(CLASS_PATH, |
|
2794 packageName, |
|
2795 classKinds, |
|
2796 false)); |
|
2797 if (wantSourceFiles) |
|
2798 fillIn(p, SOURCE_PATH, |
|
2799 fileManager.list(SOURCE_PATH, |
|
2800 packageName, |
|
2801 sourceKinds, |
|
2802 false)); |
|
2803 } |
|
2804 } |
|
2805 |
|
2806 /** |
|
2807 * Scans platform class path for files in given package. |
|
2808 */ |
|
2809 private void scanPlatformPath(PackageSymbol p) throws IOException { |
|
2810 fillIn(p, PLATFORM_CLASS_PATH, |
|
2811 fileManager.list(PLATFORM_CLASS_PATH, |
|
2812 p.fullname.toString(), |
|
2813 EnumSet.of(JavaFileObject.Kind.CLASS), |
|
2814 false)); |
|
2815 } |
|
2816 // where |
|
2817 private void fillIn(PackageSymbol p, |
|
2818 Location location, |
|
2819 Iterable<JavaFileObject> files) |
|
2820 { |
|
2821 currentLoc = location; |
|
2822 for (JavaFileObject fo : files) { |
|
2823 switch (fo.getKind()) { |
|
2824 case CLASS: |
|
2825 case SOURCE: { |
|
2826 // TODO pass binaryName to includeClassFile |
|
2827 String binaryName = fileManager.inferBinaryName(currentLoc, fo); |
|
2828 String simpleName = binaryName.substring(binaryName.lastIndexOf(".") + 1); |
|
2829 if (SourceVersion.isIdentifier(simpleName) || |
|
2830 simpleName.equals("package-info")) |
|
2831 includeClassFile(p, fo); |
|
2832 break; |
|
2833 } |
|
2834 default: |
|
2835 extraFileActions(p, fo); |
|
2836 } |
|
2837 } |
|
2838 } |
|
2839 |
2434 |
2840 /** Output for "-checkclassfile" option. |
2435 /** Output for "-checkclassfile" option. |
2841 * @param key The key to look up the correct internationalized string. |
2436 * @param key The key to look up the correct internationalized string. |
2842 * @param arg An argument for substitution into the output string. |
2437 * @param arg An argument for substitution into the output string. |
2843 */ |
2438 */ |
2844 private void printCCF(String key, Object arg) { |
2439 private void printCCF(String key, Object arg) { |
2845 log.printLines(key, arg); |
2440 log.printLines(key, arg); |
2846 } |
|
2847 |
|
2848 |
|
2849 public interface SourceCompleter { |
|
2850 void complete(ClassSymbol sym) |
|
2851 throws CompletionFailure; |
|
2852 } |
2441 } |
2853 |
2442 |
2854 /** |
2443 /** |
2855 * A subclass of JavaFileObject for the sourcefile attribute found in a classfile. |
2444 * A subclass of JavaFileObject for the sourcefile attribute found in a classfile. |
2856 * The attribute is only the last component of the original filename, so is unlikely |
2445 * The attribute is only the last component of the original filename, so is unlikely |