< prev index next >

src/jdk.compiler/share/classes/com/sun/tools/javac/code/ClassFinder.java

Print this page
rev 2988 : JDK-8058150


  33 import java.util.Set;
  34 
  35 import javax.lang.model.SourceVersion;
  36 import javax.tools.JavaFileManager;
  37 import javax.tools.JavaFileManager.Location;
  38 import javax.tools.JavaFileObject;
  39 import javax.tools.StandardJavaFileManager;
  40 
  41 import com.sun.tools.javac.code.Scope.WriteableScope;
  42 import com.sun.tools.javac.code.Symbol.ClassSymbol;
  43 import com.sun.tools.javac.code.Symbol.Completer;
  44 import com.sun.tools.javac.code.Symbol.CompletionFailure;
  45 import com.sun.tools.javac.code.Symbol.PackageSymbol;
  46 import com.sun.tools.javac.code.Symbol.TypeSymbol;
  47 import com.sun.tools.javac.comp.Annotate;
  48 import com.sun.tools.javac.comp.Enter;
  49 import com.sun.tools.javac.file.JRTIndex;
  50 import com.sun.tools.javac.file.JavacFileManager;
  51 import com.sun.tools.javac.jvm.ClassReader;
  52 import com.sun.tools.javac.jvm.Profile;

  53 import com.sun.tools.javac.util.*;
  54 
  55 import static javax.tools.StandardLocation.*;
  56 
  57 import static com.sun.tools.javac.code.Flags.*;
  58 import static com.sun.tools.javac.code.Kinds.Kind.*;
  59 
  60 import static com.sun.tools.javac.main.Option.*;

  61 import com.sun.tools.javac.util.Dependencies.CompletionCause;
  62 
  63 /**
  64  *  This class provides operations to locate class definitions
  65  *  from the source and class files on the paths provided to javac.
  66  *
  67  *  <p><b>This is NOT part of any supported API.
  68  *  If you write code that depends on this, you do so at your own risk.
  69  *  This code and its internal interfaces are subject to change or
  70  *  deletion without notice.</b>
  71  */
  72 public class ClassFinder {
  73     /** The context key for the class finder. */
  74     protected static final Context.Key<ClassFinder> classFinderKey = new Context.Key<>();
  75 
  76     ClassReader reader;
  77 
  78     private final Annotate annotate;
  79 
  80     /** Switch: verbose output.
  81      */
  82     boolean verbose;
  83 
  84     /**
  85      * Switch: cache completion failures unless -XDdev is used
  86      */
  87     private boolean cacheCompletionFailure;
  88 
  89     /**
  90      * Switch: prefer source files instead of newer when both source
  91      * and class are available
  92      **/
  93     protected boolean preferSource;
  94 
  95     /**
  96      * Switch: Search classpath and sourcepath for classes before the
  97      * bootclasspath
  98      */
  99     protected boolean userPathsFirst;
 100 





 101     /** The log to use for verbose output
 102      */
 103     final Log log;
 104 
 105     /** The symbol table. */
 106     Symtab syms;
 107 
 108     /** The name table. */
 109     final Names names;
 110 
 111     /** Force a completion failure on this name
 112      */
 113     final Name completionFailureName;
 114 
 115     /** Access to files
 116      */
 117     private final JavaFileManager fileManager;
 118 
 119     /** Dependency tracker
 120      */


 175     /** Construct a new class reader. */
 176     protected ClassFinder(Context context) {
 177         context.put(classFinderKey, this);
 178         reader = ClassReader.instance(context);
 179         names = Names.instance(context);
 180         syms = Symtab.instance(context);
 181         fileManager = context.get(JavaFileManager.class);
 182         dependencies = Dependencies.instance(context);
 183         if (fileManager == null)
 184             throw new AssertionError("FileManager initialization error");
 185         diagFactory = JCDiagnostic.Factory.instance(context);
 186 
 187         log = Log.instance(context);
 188         annotate = Annotate.instance(context);
 189 
 190         Options options = Options.instance(context);
 191         verbose = options.isSet(VERBOSE);
 192         cacheCompletionFailure = options.isUnset("dev");
 193         preferSource = "source".equals(options.get("-Xprefer"));
 194         userPathsFirst = options.isSet(XXUSERPATHSFIRST);

 195 
 196         completionFailureName =
 197             options.isSet("failcomplete")
 198             ? names.fromString(options.get("failcomplete"))
 199             : null;
 200 
 201         // Temporary, until more info is available from the module system.
 202         boolean useCtProps;
 203         JavaFileManager fm = context.get(JavaFileManager.class);
 204         if (fm instanceof JavacFileManager) {
 205             JavacFileManager jfm = (JavacFileManager) fm;
 206             useCtProps = jfm.isDefaultBootClassPath() && jfm.isSymbolFileEnabled();
 207         } else if (fm.getClass().getName().equals("com.sun.tools.sjavac.comp.SmartFileManager")) {
 208             useCtProps = !options.isSet("ignore.symbol.file");
 209         } else {
 210             useCtProps = false;
 211         }
 212         jrtIndex = useCtProps && JRTIndex.isAvailable() ? JRTIndex.getSharedInstance() : null;
 213 
 214         profile = Profile.instance(context);


 320 
 321     /** Fill in definition of class `c' from corresponding class or
 322      *  source file.
 323      */
 324     private void fillIn(ClassSymbol c) {
 325         if (completionFailureName == c.fullname) {
 326             throw new CompletionFailure(c, "user-selected completion failure by class name");
 327         }
 328         currentOwner = c;
 329         JavaFileObject classfile = c.classfile;
 330         if (classfile != null) {
 331             JavaFileObject previousClassFile = currentClassFile;
 332             try {
 333                 if (reader.filling) {
 334                     Assert.error("Filling " + classfile.toUri() + " during " + previousClassFile);
 335                 }
 336                 currentClassFile = classfile;
 337                 if (verbose) {
 338                     log.printVerbose("loading", currentClassFile.toString());
 339                 }
 340                 if (classfile.getKind() == JavaFileObject.Kind.CLASS) {

 341                     reader.readClassFile(c);
 342                     c.flags_field |= getSupplementaryFlags(c);
 343                 } else {
 344                     if (!sourceCompleter.isTerminal()) {
 345                         sourceCompleter.complete(c);
 346                     } else {
 347                         throw new IllegalStateException("Source completer required to read "
 348                                                         + classfile.toUri());
 349                     }
 350                 }
 351             } finally {
 352                 currentClassFile = previousClassFile;
 353             }
 354         } else {
 355             throw classFileNotFound(c);
 356         }
 357     }
 358     // where
 359         private CompletionFailure classFileNotFound(ClassSymbol c) {
 360             JCDiagnostic diag =


 401             }
 402         }
 403         return c;
 404     }
 405 
 406 /************************************************************************
 407  * Loading Packages
 408  ***********************************************************************/
 409 
 410     /** Include class corresponding to given class file in package,
 411      *  unless (1) we already have one the same kind (.class or .java), or
 412      *         (2) we have one of the other kind, and the given class file
 413      *             is older.
 414      */
 415     protected void includeClassFile(PackageSymbol p, JavaFileObject file) {
 416         if ((p.flags_field & EXISTS) == 0)
 417             for (Symbol q = p; q != null && q.kind == PCK; q = q.owner)
 418                 q.flags_field |= EXISTS;
 419         JavaFileObject.Kind kind = file.getKind();
 420         int seen;
 421         if (kind == JavaFileObject.Kind.CLASS)
 422             seen = CLASS_SEEN;
 423         else
 424             seen = SOURCE_SEEN;
 425         String binaryName = fileManager.inferBinaryName(currentLoc, file);
 426         int lastDot = binaryName.lastIndexOf(".");
 427         Name classname = names.fromString(binaryName.substring(lastDot + 1));
 428         boolean isPkgInfo = classname == names.package_info;
 429         ClassSymbol c = isPkgInfo
 430             ? p.package_info
 431             : (ClassSymbol) p.members_field.findFirst(classname);
 432         if (c == null) {
 433             c = syms.enterClass(classname, p);
 434             if (c.classfile == null) // only update the file if's it's newly created
 435                 c.classfile = file;
 436             if (isPkgInfo) {
 437                 p.package_info = c;
 438             } else {
 439                 if (c.owner == p)  // it might be an inner class
 440                     p.members_field.enter(c);
 441             }


 564                        fileManager.list(CLASS_PATH,
 565                                         packageName,
 566                                         classKinds,
 567                                         false));
 568             if (wantSourceFiles)
 569                 fillIn(p, SOURCE_PATH,
 570                        fileManager.list(SOURCE_PATH,
 571                                         packageName,
 572                                         sourceKinds,
 573                                         false));
 574         }
 575     }
 576 
 577     /**
 578      * Scans platform class path for files in given package.
 579      */
 580     private void scanPlatformPath(PackageSymbol p) throws IOException {
 581         fillIn(p, PLATFORM_CLASS_PATH,
 582                fileManager.list(PLATFORM_CLASS_PATH,
 583                                 p.fullname.toString(),
 584                                 EnumSet.of(JavaFileObject.Kind.CLASS),


 585                                 false));
 586     }
 587     // where

 588         private void fillIn(PackageSymbol p,
 589                             Location location,
 590                             Iterable<JavaFileObject> files)
 591         {
 592             currentLoc = location;
 593             for (JavaFileObject fo : files) {
 594                 switch (fo.getKind()) {









 595                 case CLASS:
 596                 case SOURCE: {
 597                     // TODO pass binaryName to includeClassFile
 598                     String binaryName = fileManager.inferBinaryName(currentLoc, fo);
 599                     String simpleName = binaryName.substring(binaryName.lastIndexOf(".") + 1);
 600                     if (SourceVersion.isIdentifier(simpleName) ||
 601                         simpleName.equals("package-info"))
 602                         includeClassFile(p, fo);
 603                     break;
 604                 }
 605                 default:
 606                     extraFileActions(p, fo);
 607                 }
 608             }
 609         }
 610 
 611     /**
 612      * Used for bad class definition files, such as bad .class files or
 613      * for .java files with unexpected package or class names.
 614      */


  33 import java.util.Set;
  34 
  35 import javax.lang.model.SourceVersion;
  36 import javax.tools.JavaFileManager;
  37 import javax.tools.JavaFileManager.Location;
  38 import javax.tools.JavaFileObject;
  39 import javax.tools.StandardJavaFileManager;
  40 
  41 import com.sun.tools.javac.code.Scope.WriteableScope;
  42 import com.sun.tools.javac.code.Symbol.ClassSymbol;
  43 import com.sun.tools.javac.code.Symbol.Completer;
  44 import com.sun.tools.javac.code.Symbol.CompletionFailure;
  45 import com.sun.tools.javac.code.Symbol.PackageSymbol;
  46 import com.sun.tools.javac.code.Symbol.TypeSymbol;
  47 import com.sun.tools.javac.comp.Annotate;
  48 import com.sun.tools.javac.comp.Enter;
  49 import com.sun.tools.javac.file.JRTIndex;
  50 import com.sun.tools.javac.file.JavacFileManager;
  51 import com.sun.tools.javac.jvm.ClassReader;
  52 import com.sun.tools.javac.jvm.Profile;
  53 import com.sun.tools.javac.platform.PlatformProvider;
  54 import com.sun.tools.javac.util.*;
  55 
  56 import static javax.tools.StandardLocation.*;
  57 
  58 import static com.sun.tools.javac.code.Flags.*;
  59 import static com.sun.tools.javac.code.Kinds.Kind.*;
  60 
  61 import static com.sun.tools.javac.main.Option.*;
  62 
  63 import com.sun.tools.javac.util.Dependencies.CompletionCause;
  64 
  65 /**
  66  *  This class provides operations to locate class definitions
  67  *  from the source and class files on the paths provided to javac.
  68  *
  69  *  <p><b>This is NOT part of any supported API.
  70  *  If you write code that depends on this, you do so at your own risk.
  71  *  This code and its internal interfaces are subject to change or
  72  *  deletion without notice.</b>
  73  */
  74 public class ClassFinder {
  75     /** The context key for the class finder. */
  76     protected static final Context.Key<ClassFinder> classFinderKey = new Context.Key<>();
  77 
  78     ClassReader reader;
  79 
  80     private final Annotate annotate;
  81 
  82     /** Switch: verbose output.
  83      */
  84     boolean verbose;
  85 
  86     /**
  87      * Switch: cache completion failures unless -XDdev is used
  88      */
  89     private boolean cacheCompletionFailure;
  90 
  91     /**
  92      * Switch: prefer source files instead of newer when both source
  93      * and class are available
  94      **/
  95     protected boolean preferSource;
  96 
  97     /**
  98      * Switch: Search classpath and sourcepath for classes before the
  99      * bootclasspath
 100      */
 101     protected boolean userPathsFirst;
 102 
 103     /**
 104      * Switch: should read OTHER classfiles (.sig files) from PLATFORM_CLASS_PATH.
 105      */
 106     private boolean allowSigFiles;
 107 
 108     /** The log to use for verbose output
 109      */
 110     final Log log;
 111 
 112     /** The symbol table. */
 113     Symtab syms;
 114 
 115     /** The name table. */
 116     final Names names;
 117 
 118     /** Force a completion failure on this name
 119      */
 120     final Name completionFailureName;
 121 
 122     /** Access to files
 123      */
 124     private final JavaFileManager fileManager;
 125 
 126     /** Dependency tracker
 127      */


 182     /** Construct a new class reader. */
 183     protected ClassFinder(Context context) {
 184         context.put(classFinderKey, this);
 185         reader = ClassReader.instance(context);
 186         names = Names.instance(context);
 187         syms = Symtab.instance(context);
 188         fileManager = context.get(JavaFileManager.class);
 189         dependencies = Dependencies.instance(context);
 190         if (fileManager == null)
 191             throw new AssertionError("FileManager initialization error");
 192         diagFactory = JCDiagnostic.Factory.instance(context);
 193 
 194         log = Log.instance(context);
 195         annotate = Annotate.instance(context);
 196 
 197         Options options = Options.instance(context);
 198         verbose = options.isSet(VERBOSE);
 199         cacheCompletionFailure = options.isUnset("dev");
 200         preferSource = "source".equals(options.get("-Xprefer"));
 201         userPathsFirst = options.isSet(XXUSERPATHSFIRST);
 202         allowSigFiles = context.get(PlatformProvider.class) != null;
 203 
 204         completionFailureName =
 205             options.isSet("failcomplete")
 206             ? names.fromString(options.get("failcomplete"))
 207             : null;
 208 
 209         // Temporary, until more info is available from the module system.
 210         boolean useCtProps;
 211         JavaFileManager fm = context.get(JavaFileManager.class);
 212         if (fm instanceof JavacFileManager) {
 213             JavacFileManager jfm = (JavacFileManager) fm;
 214             useCtProps = jfm.isDefaultBootClassPath() && jfm.isSymbolFileEnabled();
 215         } else if (fm.getClass().getName().equals("com.sun.tools.sjavac.comp.SmartFileManager")) {
 216             useCtProps = !options.isSet("ignore.symbol.file");
 217         } else {
 218             useCtProps = false;
 219         }
 220         jrtIndex = useCtProps && JRTIndex.isAvailable() ? JRTIndex.getSharedInstance() : null;
 221 
 222         profile = Profile.instance(context);


 328 
 329     /** Fill in definition of class `c' from corresponding class or
 330      *  source file.
 331      */
 332     private void fillIn(ClassSymbol c) {
 333         if (completionFailureName == c.fullname) {
 334             throw new CompletionFailure(c, "user-selected completion failure by class name");
 335         }
 336         currentOwner = c;
 337         JavaFileObject classfile = c.classfile;
 338         if (classfile != null) {
 339             JavaFileObject previousClassFile = currentClassFile;
 340             try {
 341                 if (reader.filling) {
 342                     Assert.error("Filling " + classfile.toUri() + " during " + previousClassFile);
 343                 }
 344                 currentClassFile = classfile;
 345                 if (verbose) {
 346                     log.printVerbose("loading", currentClassFile.toString());
 347                 }
 348                 if (classfile.getKind() == JavaFileObject.Kind.CLASS ||
 349                     classfile.getKind() == JavaFileObject.Kind.OTHER) {
 350                     reader.readClassFile(c);
 351                     c.flags_field |= getSupplementaryFlags(c);
 352                 } else {
 353                     if (!sourceCompleter.isTerminal()) {
 354                         sourceCompleter.complete(c);
 355                     } else {
 356                         throw new IllegalStateException("Source completer required to read "
 357                                                         + classfile.toUri());
 358                     }
 359                 }
 360             } finally {
 361                 currentClassFile = previousClassFile;
 362             }
 363         } else {
 364             throw classFileNotFound(c);
 365         }
 366     }
 367     // where
 368         private CompletionFailure classFileNotFound(ClassSymbol c) {
 369             JCDiagnostic diag =


 410             }
 411         }
 412         return c;
 413     }
 414 
 415 /************************************************************************
 416  * Loading Packages
 417  ***********************************************************************/
 418 
 419     /** Include class corresponding to given class file in package,
 420      *  unless (1) we already have one the same kind (.class or .java), or
 421      *         (2) we have one of the other kind, and the given class file
 422      *             is older.
 423      */
 424     protected void includeClassFile(PackageSymbol p, JavaFileObject file) {
 425         if ((p.flags_field & EXISTS) == 0)
 426             for (Symbol q = p; q != null && q.kind == PCK; q = q.owner)
 427                 q.flags_field |= EXISTS;
 428         JavaFileObject.Kind kind = file.getKind();
 429         int seen;
 430         if (kind == JavaFileObject.Kind.CLASS || kind == JavaFileObject.Kind.OTHER)
 431             seen = CLASS_SEEN;
 432         else
 433             seen = SOURCE_SEEN;
 434         String binaryName = fileManager.inferBinaryName(currentLoc, file);
 435         int lastDot = binaryName.lastIndexOf(".");
 436         Name classname = names.fromString(binaryName.substring(lastDot + 1));
 437         boolean isPkgInfo = classname == names.package_info;
 438         ClassSymbol c = isPkgInfo
 439             ? p.package_info
 440             : (ClassSymbol) p.members_field.findFirst(classname);
 441         if (c == null) {
 442             c = syms.enterClass(classname, p);
 443             if (c.classfile == null) // only update the file if's it's newly created
 444                 c.classfile = file;
 445             if (isPkgInfo) {
 446                 p.package_info = c;
 447             } else {
 448                 if (c.owner == p)  // it might be an inner class
 449                     p.members_field.enter(c);
 450             }


 573                        fileManager.list(CLASS_PATH,
 574                                         packageName,
 575                                         classKinds,
 576                                         false));
 577             if (wantSourceFiles)
 578                 fillIn(p, SOURCE_PATH,
 579                        fileManager.list(SOURCE_PATH,
 580                                         packageName,
 581                                         sourceKinds,
 582                                         false));
 583         }
 584     }
 585 
 586     /**
 587      * Scans platform class path for files in given package.
 588      */
 589     private void scanPlatformPath(PackageSymbol p) throws IOException {
 590         fillIn(p, PLATFORM_CLASS_PATH,
 591                fileManager.list(PLATFORM_CLASS_PATH,
 592                                 p.fullname.toString(),
 593                                 allowSigFiles ? EnumSet.of(JavaFileObject.Kind.CLASS,
 594                                                            JavaFileObject.Kind.OTHER)
 595                                               : EnumSet.of(JavaFileObject.Kind.CLASS),
 596                                 false));
 597     }
 598     // where
 599         @SuppressWarnings("fallthrough")
 600         private void fillIn(PackageSymbol p,
 601                             Location location,
 602                             Iterable<JavaFileObject> files)
 603         {
 604             currentLoc = location;
 605             for (JavaFileObject fo : files) {
 606                 switch (fo.getKind()) {
 607                 case OTHER:
 608                     boolean sigFile = location == PLATFORM_CLASS_PATH &&
 609                                       allowSigFiles &&
 610                                       fo.getName().endsWith(".sig");
 611                     if (!sigFile) {
 612                         extraFileActions(p, fo);
 613                         break;
 614                     }
 615                     //intentional fall-through:
 616                 case CLASS:
 617                 case SOURCE: {
 618                     // TODO pass binaryName to includeClassFile
 619                     String binaryName = fileManager.inferBinaryName(currentLoc, fo);
 620                     String simpleName = binaryName.substring(binaryName.lastIndexOf(".") + 1);
 621                     if (SourceVersion.isIdentifier(simpleName) ||
 622                         simpleName.equals("package-info"))
 623                         includeClassFile(p, fo);
 624                     break;
 625                 }
 626                 default:
 627                     extraFileActions(p, fo);
 628                 }
 629             }
 630         }
 631 
 632     /**
 633      * Used for bad class definition files, such as bad .class files or
 634      * for .java files with unexpected package or class names.
 635      */
< prev index next >