Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/sun/tools/java/Imports.java
38918 views
/*1* Copyright (c) 1994, 2003, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package sun.tools.java;2627import java.util.Hashtable;28import java.util.Vector;29import java.util.Enumeration;30import java.util.List;31import java.util.Collections;32import java.io.IOException;3334/**35* This class describes the classes and packages imported36* from a source file. A Hashtable called bindings is maintained37* to quickly map symbol names to classes. This table is flushed38* everytime a new import is added.39*40* A class name is resolved as follows:41* - if it is a qualified name then return the corresponding class42* - if the name corresponds to an individually imported class then return that class43* - check if the class is defined in any of the imported packages,44* if it is then return it, make sure it is defined in only one package45* - assume that the class is defined in the current package46*47* WARNING: The contents of this source file are not part of any48* supported API. Code that depends on them does so at its own risk:49* they are subject to change or removal without notice.50*/5152public53class Imports implements Constants {54/**55* The current package, which is implicitly imported,56* and has precedence over other imported packages.57*/58Identifier currentPackage = idNull;5960/**61* A location for the current package declaration. Used to62* report errors against the current package.63*/64long currentPackageWhere = 0;6566/**67* The imported classes, including memoized imports from packages.68*/69Hashtable classes = new Hashtable();7071/**72* The imported package identifiers. This will not contain duplicate73* imports for the same package. It will also not contain the74* current package.75*/76Vector packages = new Vector();7778/**79* The (originally) imported classes.80* A vector of IdentifierToken.81*/82Vector singles = new Vector();8384/**85* Are the import names checked yet?86*/87protected int checked;8889/**90* Constructor, always import java.lang.91*/92public Imports(Environment env) {93addPackage(idJavaLang);94}9596/**97* Check the names of the imports.98*/99public synchronized void resolve(Environment env) {100if (checked != 0) {101return;102}103checked = -1;104105// After all class information has been read, now we can106// safely inspect import information for errors.107// If we did this before all parsing was finished,108// we could get vicious circularities, since files can109// import each others' classes.110111// A note: the resolution of the package java.lang takes place112// in the sun.tools.javac.BatchEnvironment#setExemptPackages().113114// Make sure that the current package's name does not collide115// with the name of an existing class. (bug 4101529)116//117// This change has been backed out because, on WIN32, it118// failed to distinguish between java.awt.event and119// java.awt.Event when looking for a directory. We will120// add this back in later.121//122// if (currentPackage != idNull) {123// Identifier resolvedName =124// env.resolvePackageQualifiedName(currentPackage);125//126// Identifier className = resolvedName.getTopName();127//128// if (importable(className, env)) {129// // The name of the current package is also the name130// // of a class.131// env.error(currentPackageWhere, "package.class.conflict",132// currentPackage, className);133// }134// }135136Vector resolvedPackages = new Vector();137for (Enumeration e = packages.elements() ; e.hasMoreElements() ;) {138IdentifierToken t = (IdentifierToken)e.nextElement();139Identifier nm = t.getName();140long where = t.getWhere();141142// Check to see if this package is exempt from the "exists"143// check. See the note in144// sun.tools.javac.BatchEnvironment#setExemptPackages()145// for more information.146if (env.isExemptPackage(nm)) {147resolvedPackages.addElement(t);148continue;149}150151// (Note: This code is moved from BatchParser.importPackage().)152try {153Identifier rnm = env.resolvePackageQualifiedName(nm);154if (importable(rnm, env)) {155// This name is a real class; better not be a package too.156if (env.getPackage(rnm.getTopName()).exists()) {157env.error(where, "class.and.package",158rnm.getTopName());159}160// Pass an "inner" name to the imports.161if (!rnm.isInner())162rnm = Identifier.lookupInner(rnm, idNull);163nm = rnm;164} else if (!env.getPackage(nm).exists()) {165env.error(where, "package.not.found", nm, "import");166} else if (rnm.isInner()) {167// nm exists, and rnm.getTopName() is a parent package168env.error(where, "class.and.package", rnm.getTopName());169}170resolvedPackages.addElement(new IdentifierToken(where, nm));171} catch (IOException ee) {172env.error(where, "io.exception", "import");173}174}175packages = resolvedPackages;176177for (Enumeration e = singles.elements() ; e.hasMoreElements() ;) {178IdentifierToken t = (IdentifierToken)e.nextElement();179Identifier nm = t.getName();180long where = t.getWhere();181Identifier pkg = nm.getQualifier();182183// (Note: This code is moved from BatchParser.importClass().)184nm = env.resolvePackageQualifiedName(nm);185if (!env.classExists(nm.getTopName())) {186env.error(where, "class.not.found", nm, "import");187}188189// (Note: This code is moved from Imports.addClass().)190Identifier snm = nm.getFlatName().getName();191192// make sure it isn't already imported explicitly193Identifier className = (Identifier)classes.get(snm);194if (className != null) {195Identifier f1 = Identifier.lookup(className.getQualifier(),196className.getFlatName());197Identifier f2 = Identifier.lookup(nm.getQualifier(),198nm.getFlatName());199if (!f1.equals(f2)) {200env.error(where, "ambig.class", nm, className);201}202}203classes.put(snm, nm);204205206// The code here needs to check to see, if we207// are importing an inner class, that all of its208// enclosing classes are visible to us. To check this,209// we need to construct a definition for the class.210// The code here used to call...211//212// ClassDefinition def = env.getClassDefinition(nm);213//214// ...but that interfered with the basicCheck()'ing of215// interfaces in certain cases (bug no. 4086139). Never216// fear. Instead we load the class with a call to the217// new getClassDefinitionNoCheck() which does no basicCheck() and218// lets us answer the questions we are interested in w/o219// interfering with the demand-driven nature of basicCheck().220221try {222// Get a declaration223ClassDeclaration decl = env.getClassDeclaration(nm);224225// Get the definition (no env argument)226ClassDefinition def = decl.getClassDefinitionNoCheck(env);227228// Get the true name of the package containing this class.229// `pkg' from above is insufficient. It includes the230// names of our enclosing classes. Fix for 4086815.231Identifier importedPackage = def.getName().getQualifier();232233// Walk out the outerClass chain, ensuring that each level234// is visible from our perspective.235for (; def != null; def = def.getOuterClass()) {236if (def.isPrivate()237|| !(def.isPublic()238|| importedPackage.equals(currentPackage))) {239env.error(where, "cant.access.class", def);240break;241}242}243} catch (AmbiguousClass ee) {244env.error(where, "ambig.class", ee.name1, ee.name2);245} catch (ClassNotFound ee) {246env.error(where, "class.not.found", ee.name, "import");247}248}249checked = 1;250}251252/**253* Lookup a class, given the current set of imports,254* AmbiguousClass exception is thrown if the name can be255* resolved in more than one way. A ClassNotFound exception256* is thrown if the class is not found in the imported classes257* and packages.258*/259public synchronized Identifier resolve(Environment env, Identifier nm) throws ClassNotFound {260if (tracing) env.dtEnter("Imports.resolve: " + nm);261262// If the class has the special ambiguous prefix, then we will263// get the original AmbiguousClass exception by removing the264// prefix and proceeding in the normal fashion.265// (part of solution for 4059855)266if (nm.hasAmbigPrefix()) {267nm = nm.removeAmbigPrefix();268}269270if (nm.isQualified()) {271// Don't bother it is already qualified272if (tracing) env.dtExit("Imports.resolve: QUALIFIED " + nm);273return nm;274}275276if (checked <= 0) {277checked = 0;278resolve(env);279}280281// Check if it was imported before282Identifier className = (Identifier)classes.get(nm);283if (className != null) {284if (tracing) env.dtExit("Imports.resolve: PREVIOUSLY IMPORTED " + nm);285return className;286}287288// Note: the section below has changed a bit during the fix289// for bug 4093217. The current package is no longer grouped290// with the rest of the import-on-demands; it is now checked291// separately. Also, the list of import-on-demands is now292// guarranteed to be duplicate-free, so the code below can afford293// to be a bit simpler.294295// First we look in the current package. The current package296// is given precedence over the rest of the import-on-demands,297// which means, among other things, that a class in the current298// package cannot be ambiguous.299Identifier id = Identifier.lookup(currentPackage, nm);300if (importable(id, env)) {301className = id;302} else {303// If it isn't in the current package, try to find it in304// our import-on-demands.305Enumeration e = packages.elements();306while (e.hasMoreElements()) {307IdentifierToken t = (IdentifierToken)e.nextElement();308id = Identifier.lookup(t.getName(), nm);309310if (importable(id, env)) {311if (className == null) {312// We haven't found any other matching classes yet.313// Set className to what we've found and continue314// looking for an ambiguity.315className = id;316} else {317if (tracing)318env.dtExit("Imports.resolve: AMBIGUOUS " + nm);319320// We've found an ambiguity.321throw new AmbiguousClass(className, id);322}323}324}325}326327// Make sure a class was found328if (className == null) {329if (tracing) env.dtExit("Imports.resolve: NOT FOUND " + nm);330throw new ClassNotFound(nm);331}332333// Remember the binding334classes.put(nm, className);335if (tracing) env.dtExit("Imports.resolve: FIRST IMPORT " + nm);336return className;337}338339/**340* Check to see if 'id' names an importable class in `env'.341* This method was made public and static for utility.342*/343static public boolean importable(Identifier id, Environment env) {344if (!id.isInner()) {345return env.classExists(id);346} else if (!env.classExists(id.getTopName())) {347return false;348} else {349// load the top class and look inside it350try {351// There used to be a call to...352// env.getClassDeclaration(id.getTopName());353// ...here. It has been replaced with the354// two statements below. These should be functionally355// the same except for the fact that356// getClassDefinitionNoCheck() does not call357// basicCheck(). This allows us to avoid a circular358// need to do basicChecking that can arise with359// certain patterns of importing and inheritance.360// This is a fix for a variant of bug 4086139.361//362// Note: the special case code in env.getClassDefinition()363// which handles inner class names is not replicated below.364// This should be okay, as we are looking up id.getTopName(),365// not id.366ClassDeclaration decl =367env.getClassDeclaration(id.getTopName());368ClassDefinition c =369decl.getClassDefinitionNoCheck(env);370371return c.innerClassExists(id.getFlatName().getTail());372} catch (ClassNotFound ee) {373return false;374}375}376}377378/**379* Suppose a resolve() call has failed.380* This routine can be used silently to give a reasonable381* default qualification (the current package) to the identifier.382* This decision is recorded for future reference.383*/384public synchronized Identifier forceResolve(Environment env, Identifier nm) {385if (nm.isQualified())386return nm;387388Identifier className = (Identifier)classes.get(nm);389if (className != null) {390return className;391}392393className = Identifier.lookup(currentPackage, nm);394395classes.put(nm, className);396return className;397}398399/**400* Add a class import401*/402public synchronized void addClass(IdentifierToken t) {403singles.addElement(t);404}405// for compatibility406public void addClass(Identifier nm) throws AmbiguousClass {407addClass(new IdentifierToken(nm));408}409410/**411* Add a package import, or perhaps an inner class scope.412* Ignore any duplicate imports.413*/414public synchronized void addPackage(IdentifierToken t) {415final Identifier name = t.getName();416417// If this is a duplicate import for the current package,418// ignore it.419if (name == currentPackage) {420return;421}422423// If this is a duplicate of a package which has already been424// added to the list, ignore it.425final int size = packages.size();426for (int i = 0; i < size; i++) {427if (name == ((IdentifierToken)packages.elementAt(i)).getName()) {428return;429}430}431432// Add the package to the list.433packages.addElement(t);434}435// for compatibility436public void addPackage(Identifier id) {437addPackage(new IdentifierToken(id));438}439440/**441* Specify the current package with an IdentifierToken.442*/443public synchronized void setCurrentPackage(IdentifierToken t) {444currentPackage = t.getName();445currentPackageWhere = t.getWhere();446}447448/**449* Specify the current package450*/451public synchronized void setCurrentPackage(Identifier id) {452currentPackage = id;453}454455/**456* Report the current package457*/458public Identifier getCurrentPackage() {459return currentPackage;460}461462/**463* Return an unmodifiable list of IdentifierToken representing464* packages specified as imports.465*/466public List getImportedPackages() {467return Collections.unmodifiableList(packages);468}469470/**471* Return an unmodifiable list of IdentifierToken representing472* classes specified as imports.473*/474public List getImportedClasses() {475return Collections.unmodifiableList(singles);476}477478/**479* Extend an environment with my resolve() method.480*/481public Environment newEnvironment(Environment env) {482return new ImportEnvironment(env, this);483}484}485486final487class ImportEnvironment extends Environment {488Imports imports;489490ImportEnvironment(Environment env, Imports imports) {491super(env, env.getSource());492this.imports = imports;493}494495public Identifier resolve(Identifier nm) throws ClassNotFound {496return imports.resolve(this, nm);497}498499public Imports getImports() {500return imports;501}502}503504505