Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/sun/tools/javac/BatchEnvironment.java
38918 views
/*1* Copyright (c) 1994, 2004, 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.javac;2627import sun.tools.java.*;28import sun.tools.tree.Node;29import sun.tools.java.Package;3031import java.util.*;32import java.io.*;3334/**35* Main environment of the batch version of the Java compiler,36* this needs more work.37*38* WARNING: The contents of this source file are not part of any39* supported API. Code that depends on them does so at its own risk:40* they are subject to change or removal without notice.41*/42@Deprecated43public44class BatchEnvironment extends Environment implements ErrorConsumer {45/**46* The stream where error message are printed.47*/48OutputStream out;4950/**51* The path we use for finding source files.52*/53protected ClassPath sourcePath;5455/**56* The path we use for finding class (binary) files.57*/58protected ClassPath binaryPath;5960/**61* A hashtable of resource contexts.62*/63Hashtable packages = new Hashtable(31);6465/**66* The classes, in order of appearance.67*/68Vector classesOrdered = new Vector();6970/**71* The classes, keyed by ClassDeclaration.72*/73Hashtable classes = new Hashtable(351);7475/**76* flags77*/78public int flags;7980/**81* Major and minor versions to use for generated class files.82* Environments that extend BatchEnvironment (such as javadoc's83* Env class) get the default values below.84*85* javac itself may override these versions with values determined86* from the command line "-target" option.87*/88public short majorVersion = JAVA_DEFAULT_VERSION;89public short minorVersion = JAVA_DEFAULT_MINOR_VERSION;9091// JCOV92/**93* coverage data file94*/95public File covFile;96// end JCOV9798/**99* The number of errors and warnings100*/101public int nerrors;102public int nwarnings;103public int ndeprecations;104105/**106* A list of files containing deprecation warnings.107*/108Vector deprecationFiles = new Vector();109110/**111* writes out error messages112*/113114ErrorConsumer errorConsumer;115116/**117* Old constructors -- these constructors build a BatchEnvironment118* with an old-style class path.119*/120public BatchEnvironment(ClassPath path) {121this(System.out, path);122}123public BatchEnvironment(OutputStream out,124ClassPath path) {125this(out, path, (ErrorConsumer) null);126}127public BatchEnvironment(OutputStream out,128ClassPath path,129ErrorConsumer errorConsumer) {130this(out, path, path, errorConsumer);131}132133/**134* New constructors -- these constructors build a BatchEnvironment135* with a source path and a binary path.136*/137public BatchEnvironment(ClassPath sourcePath,138ClassPath binaryPath) {139this(System.out, sourcePath, binaryPath);140}141public BatchEnvironment(OutputStream out,142ClassPath sourcePath,143ClassPath binaryPath) {144this(out, sourcePath, binaryPath, (ErrorConsumer) null);145}146public BatchEnvironment(OutputStream out,147ClassPath sourcePath,148ClassPath binaryPath,149ErrorConsumer errorConsumer) {150this.out = out;151this.sourcePath = sourcePath;152this.binaryPath = binaryPath;153this.errorConsumer = (errorConsumer == null) ? this : errorConsumer;154}155156/**157* Factory158*/159static BatchEnvironment create(OutputStream out,160String srcPathString,161String classPathString,162String sysClassPathString,163String extDirsString){164ClassPath[] classPaths = classPaths(srcPathString, classPathString,165sysClassPathString, extDirsString);166return new BatchEnvironment(out, classPaths[0], classPaths[1]);167}168169protected static ClassPath[] classPaths(String srcPathString,170String classPathString,171String sysClassPathString,172String extDirsString) {173// Create our source classpath and our binary classpath174ClassPath sourcePath;175ClassPath binaryPath;176StringBuffer binaryPathBuffer = new StringBuffer();177178if (classPathString == null) {179// The env.class.path property is the user's CLASSPATH180// environment variable, and it set by the wrapper (ie,181// javac.exe).182classPathString = System.getProperty("env.class.path");183if (classPathString == null) {184classPathString = ".";185}186}187if (srcPathString == null) {188srcPathString = classPathString;189}190if (sysClassPathString == null) {191sysClassPathString = System.getProperty("sun.boot.class.path");192if (sysClassPathString == null) { // shouldn't happen; recover gracefully193sysClassPathString = classPathString;194}195}196appendPath(binaryPathBuffer, sysClassPathString);197198if (extDirsString == null) {199extDirsString = System.getProperty("java.ext.dirs");200}201if (extDirsString != null) {202StringTokenizer st = new StringTokenizer(extDirsString,203File.pathSeparator);204while (st.hasMoreTokens()) {205String dirName = st.nextToken();206File dir = new File(dirName);207if (!dirName.endsWith(File.separator)) {208dirName += File.separator;209}210if (dir.isDirectory()) {211String[] files = dir.list();212for (int i = 0; i < files.length; ++i) {213String name = files[i];214if (name.endsWith(".jar")) {215appendPath(binaryPathBuffer, dirName + name);216}217}218}219}220}221222appendPath(binaryPathBuffer, classPathString);223224sourcePath = new ClassPath(srcPathString);225binaryPath = new ClassPath(binaryPathBuffer.toString());226227return new ClassPath[]{sourcePath, binaryPath};228}229230private static void appendPath(StringBuffer buf, String str) {231if (str.length() > 0) {232if (buf.length() > 0) {233buf.append(File.pathSeparator);234}235buf.append(str);236}237}238239/**240* Return flags241*/242public int getFlags() {243return flags;244}245246/**247* Return major version to use for generated class files248*/249public short getMajorVersion() {250return majorVersion;251}252253/**254* Return minor version to use for generated class files255*/256public short getMinorVersion() {257return minorVersion;258}259260// JCOV261/**262* Return coverage data file263*/264public File getcovFile() {265return covFile;266}267// end JCOV268269/**270* Return an enumeration of all the currently defined classes271* in order of appearance to getClassDeclaration().272*/273public Enumeration getClasses() {274return classesOrdered.elements();275}276277/**278* A set of Identifiers for all packages exempt from the "exists"279* check in Imports#resolve(). These are the current packages for280* all classes being compiled as of the first call to isExemptPackage.281*/282private Set exemptPackages;283284/**285* Tells whether an Identifier refers to a package which should be286* exempt from the "exists" check in Imports#resolve().287*/288public boolean isExemptPackage(Identifier id) {289if (exemptPackages == null) {290// Collect a list of the packages of all classes currently291// being compiled.292setExemptPackages();293}294295return exemptPackages.contains(id);296}297298/**299* Set the set of packages which are exempt from the exists check300* in Imports#resolve().301*/302private void setExemptPackages() {303// The JLS gives us the freedom to define "accessibility" of304// a package in whatever manner we wish. After the evaluation305// of bug 4093217, we have decided to consider a package P306// accessible if either:307//308// 1. The directory corresponding to P exists on the classpath.309// 2. For any class C currently being compiled, C belongs to310// package P.311// 3. For any class C currently being compiled, C belongs to312// package Q and Q is a subpackage of P.313//314// In order to implement this, we collect the current packages315// (and prefixes) of all packages we have found so far. These316// will be exempt from the "exists" check in317// sun.tools.java.Imports#resolve().318319exemptPackages = new HashSet(101);320321// Add all of the current packages and their prefixes to our set.322for (Enumeration e = getClasses(); e.hasMoreElements(); ) {323ClassDeclaration c = (ClassDeclaration) e.nextElement();324if (c.getStatus() == CS_PARSED) {325SourceClass def = (SourceClass) c.getClassDefinition();326if (def.isLocal())327continue;328329Identifier pkg = def.getImports().getCurrentPackage();330331// Add the name of this package and all of its prefixes332// to our set.333while (pkg != idNull && exemptPackages.add(pkg)) {334pkg = pkg.getQualifier();335}336}337}338339// Before we go any further, we make sure java.lang is340// accessible and that it is not ambiguous. These checks341// are performed for "ordinary" packages in342// sun.tools.java.Imports#resolve(). The reason we perform343// them specially for java.lang is that we want to report344// the error once, and outside of any particular file.345346// Check to see if java.lang is accessible.347if (!exemptPackages.contains(idJavaLang)) {348// Add java.lang to the set of exempt packages.349exemptPackages.add(idJavaLang);350351try {352if (!getPackage(idJavaLang).exists()) {353// java.lang doesn't exist.354error(0, "package.not.found.strong", idJavaLang);355return;356}357} catch (IOException ee) {358// We got an IO exception checking to see if the package359// java.lang exists.360error(0, "io.exception.package", idJavaLang);361}362}363364// Next we ensure that java.lang is not both a class and365// a package. (Fix for 4101529)366//367// This change has been backed out because, on WIN32, it368// failed to take character case into account. It will369// be put back in later.370//371// Identifier resolvedName =372// resolvePackageQualifiedName(idJavaLang);373// Identifier topClassName = resolvedName.getTopName();374// //if (Imports.importable(topClassName, env)) {375// if (Imports.importable(topClassName, this)) {376// // It is a package and a class. Emit the error.377// error(0, "package.class.conflict.strong",378// idJavaLang, topClassName);379// return;380// }381}382383/**384* Get a class, given the fully qualified class name385*/386public ClassDeclaration getClassDeclaration(Identifier nm) {387return getClassDeclaration(Type.tClass(nm));388}389390public ClassDeclaration getClassDeclaration(Type t) {391ClassDeclaration c = (ClassDeclaration)classes.get(t);392if (c == null) {393classes.put(t, c = new ClassDeclaration(t.getClassName()));394classesOrdered.addElement(c);395}396return c;397}398399/**400* Check if a class exists401* Applies only to package members (non-nested classes).402*/403public boolean classExists(Identifier nm) {404if (nm.isInner()) {405nm = nm.getTopName(); // just in case406}407Type t = Type.tClass(nm);408try {409ClassDeclaration c = (ClassDeclaration)classes.get(t);410return (c != null) ? c.getName().equals(nm) :411getPackage(nm.getQualifier()).classExists(nm.getName());412} catch (IOException e) {413return true;414}415}416417/**418* Generate a new name similar to the given one.419* Do it in such a way that repeated compilations of420* the same source generate the same series of names.421*/422423// This code does not perform as stated above.424// Correction below is part of fix for bug id 4056065.425//426// NOTE: The method 'generateName' has now been folded into its427// single caller, 'makeClassDefinition', which appears later in428// this file.429430/*--------------------------*431public Identifier generateName(ClassDefinition outerClass, Identifier nm) {432Identifier outerNm = outerClass.getName();433Identifier flat = outerNm.getFlatName();434Identifier stem = Identifier.lookup(outerNm.getQualifier(),435flat.getHead());436for (int i = 1; ; i++) {437String name = i + (nm.equals(idNull) ? "" : SIG_INNERCLASS + nm);438Identifier nm1 = Identifier.lookupInner(stem,439Identifier.lookup(name));440if (classes.get(Type.tClass(nm1)) == null)441return nm1;442}443}444*--------------------------*/445446/**447* Get the package path for a package448*/449public Package getPackage(Identifier pkg) throws IOException {450Package p = (Package)packages.get(pkg);451if (p == null) {452packages.put(pkg, p = new Package(sourcePath, binaryPath, pkg));453}454return p;455}456457/**458* Parse a source file459*/460public void parseFile(ClassFile file) throws FileNotFoundException {461long tm = System.currentTimeMillis();462InputStream input;463BatchParser p;464465if (tracing) dtEnter("parseFile: PARSING SOURCE " + file);466467Environment env = new Environment(this, file);468469try {470input = file.getInputStream();471env.setCharacterEncoding(getCharacterEncoding());472// p = new BatchParser(e, new BufferedInputStream(input));473p = new BatchParser(env, input);474} catch(IOException ex) {475if (tracing) dtEvent("parseFile: IO EXCEPTION " + file);476throw new FileNotFoundException();477}478479try {480p.parseFile();481} catch(Exception e) {482throw new CompilerError(e);483}484485try {486input.close();487} catch (IOException ex) {488// We're turn with the input, so ignore this.489}490491if (verbose()) {492tm = System.currentTimeMillis() - tm;493output(Main.getText("benv.parsed_in", file.getPath(),494Long.toString(tm)));495}496497if (p.classes.size() == 0) {498// The JLS allows a file to contain no compilation units --499// that is, it allows a file to contain no classes or interfaces.500// In this case, we are still responsible for checking that the501// imports resolve properly. The way the compiler is organized,502// this is the last point at which we still have enough information503// to do so. (Fix for 4041851).504p.imports.resolve(env);505} else {506// In an attempt to see that classes which come from the507// same source file are all recompiled when any one of them508// would be recompiled (when using the -depend option) we509// introduce artificial dependencies between these classes.510// We do this by calling the addDependency() method, which511// adds a (potentially unused) class reference to the constant512// pool of the class.513//514// Previously, we added a dependency from every class in the515// file, to every class in the file. This introduced, in516// total, a quadratic number of potentially bogus constant517// pool entries. This was bad. Now we add our artificial518// dependencies in such a way that the classes are connected519// in a circle. While single links is probably sufficient, the520// code below adds double links just to be diligent.521// (Fix for 4108286).522//523// Note that we don't chain in inner classes. The links524// between them and their outerclass should be sufficient525// here.526// (Fix for 4107960).527//528// The dependency code was previously in BatchParser.java.529Enumeration e = p.classes.elements();530531// first will not be an inner class.532ClassDefinition first = (ClassDefinition) e.nextElement();533if (first.isInnerClass()) {534throw new CompilerError("BatchEnvironment, first is inner");535}536537ClassDefinition current = first;538ClassDefinition next;539while (e.hasMoreElements()) {540next = (ClassDefinition) e.nextElement();541// Don't chain in inner classes.542if (next.isInnerClass()) {543continue;544}545current.addDependency(next.getClassDeclaration());546next.addDependency(current.getClassDeclaration());547current = next;548}549// Make a circle. Don't bother to add a dependency if there550// is only one class in the file.551if (current != first) {552current.addDependency(first.getClassDeclaration());553first.addDependency(current.getClassDeclaration());554}555}556557if (tracing) dtExit("parseFile: SOURCE PARSED " + file);558}559560/**561* Load a binary file562*/563BinaryClass loadFile(ClassFile file) throws IOException {564long tm = System.currentTimeMillis();565InputStream input = file.getInputStream();566BinaryClass c = null;567568if (tracing) dtEnter("loadFile: LOADING CLASSFILE " + file);569570try {571DataInputStream is =572new DataInputStream(new BufferedInputStream(input));573c = BinaryClass.load(new Environment(this, file), is,574loadFileFlags());575} catch (ClassFormatError e) {576error(0, "class.format", file.getPath(), e.getMessage());577if (tracing) dtExit("loadFile: CLASS FORMAT ERROR " + file);578return null;579} catch (java.io.EOFException e) {580// If we get an EOF while processing a class file, then581// it has been truncated. We let other I/O errors pass582// through. Fix for 4088443.583error(0, "truncated.class", file.getPath());584return null;585}586587input.close();588if (verbose()) {589tm = System.currentTimeMillis() - tm;590output(Main.getText("benv.loaded_in", file.getPath(),591Long.toString(tm)));592}593594if (tracing) dtExit("loadFile: CLASSFILE LOADED " + file);595596return c;597}598599/**600* Default flags for loadFile. Subclasses may override this.601*/602int loadFileFlags() {603return 0;604}605606/**607* Load a binary class608*/609boolean needsCompilation(Hashtable check, ClassDeclaration c) {610switch (c.getStatus()) {611612case CS_UNDEFINED:613if (tracing) dtEnter("needsCompilation: UNDEFINED " + c.getName());614loadDefinition(c);615return needsCompilation(check, c);616617case CS_UNDECIDED:618if (tracing) dtEnter("needsCompilation: UNDECIDED " + c.getName());619if (check.get(c) == null) {620check.put(c, c);621622BinaryClass bin = (BinaryClass)c.getClassDefinition();623for (Enumeration e = bin.getDependencies() ; e.hasMoreElements() ;) {624ClassDeclaration dep = (ClassDeclaration)e.nextElement();625if (needsCompilation(check, dep)) {626// It must be source, dependencies need compilation627c.setDefinition(bin, CS_SOURCE);628if (tracing) dtExit("needsCompilation: YES (source) " + c.getName());629return true;630}631}632}633if (tracing) dtExit("needsCompilation: NO (undecided) " + c.getName());634return false;635636case CS_BINARY:637if (tracing) {638dtEnter("needsCompilation: BINARY " + c.getName());639dtExit("needsCompilation: NO (binary) " + c.getName());640}641return false;642643}644645if (tracing) dtExit("needsCompilation: YES " + c.getName());646return true;647}648649/**650* Load the definition of a class651* or at least determine how to load it.652* The caller must repeat calls to this method653* until it the state converges to CS_BINARY, CS_PARSED, or the like..654* @see ClassDeclaration#getClassDefinition655*/656public void loadDefinition(ClassDeclaration c) {657if (tracing) dtEnter("loadDefinition: ENTER " +658c.getName() + ", status " + c.getStatus());659switch (c.getStatus()) {660case CS_UNDEFINED: {661if (tracing)662dtEvent("loadDefinition: STATUS IS UNDEFINED");663Identifier nm = c.getName();664Package pkg;665try {666pkg = getPackage(nm.getQualifier());667} catch (IOException e) {668// If we can't get at the package, then we'll just669// have to set the class to be not found.670c.setDefinition(null, CS_NOTFOUND);671672error(0, "io.exception", c);673if (tracing)674dtExit("loadDefinition: IO EXCEPTION (package)");675return;676}677ClassFile binfile = pkg.getBinaryFile(nm.getName());678if (binfile == null) {679// must be source, there is no binary680c.setDefinition(null, CS_SOURCE);681if (tracing)682dtExit("loadDefinition: MUST BE SOURCE (no binary) " +683c.getName());684return;685}686687ClassFile srcfile = pkg.getSourceFile(nm.getName());688if (srcfile == null) {689if (tracing)690dtEvent("loadDefinition: NO SOURCE " + c.getName());691BinaryClass bc = null;692try {693bc = loadFile(binfile);694} catch (IOException e) {695// If we can't access the binary, set the class to696// be not found. (bug id 4030497)697c.setDefinition(null, CS_NOTFOUND);698699error(0, "io.exception", binfile);700if (tracing)701dtExit("loadDefinition: IO EXCEPTION (binary)");702return;703}704if ((bc != null) && !bc.getName().equals(nm)) {705error(0, "wrong.class", binfile.getPath(), c, bc);706bc = null;707if (tracing)708dtEvent("loadDefinition: WRONG CLASS (binary)");709}710if (bc == null) {711// no source nor binary found712c.setDefinition(null, CS_NOTFOUND);713if (tracing)714dtExit("loadDefinition: NOT FOUND (source or binary)");715return;716}717718// Couldn't find the source, try the one mentioned in the binary719if (bc.getSource() != null) {720srcfile = new ClassFile(new File((String)bc.getSource()));721// Look for the source file722srcfile = pkg.getSourceFile(srcfile.getName());723if ((srcfile != null) && srcfile.exists()) {724if (tracing)725dtEvent("loadDefinition: FILENAME IN BINARY " +726srcfile);727if (srcfile.lastModified() > binfile.lastModified()) {728// must be source, it is newer than the binary729c.setDefinition(bc, CS_SOURCE);730if (tracing)731dtEvent("loadDefinition: SOURCE IS NEWER " +732srcfile);733bc.loadNested(this);734if (tracing)735dtExit("loadDefinition: MUST BE SOURCE " +736c.getName());737return;738}739if (dependencies()) {740c.setDefinition(bc, CS_UNDECIDED);741if (tracing)742dtEvent("loadDefinition: UNDECIDED " +743c.getName());744} else {745c.setDefinition(bc, CS_BINARY);746if (tracing)747dtEvent("loadDefinition: MUST BE BINARY " +748c.getName());749}750bc.loadNested(this);751if (tracing)752dtExit("loadDefinition: EXIT " +753c.getName() + ", status " + c.getStatus());754return;755}756}757758// It must be binary, there is no source759c.setDefinition(bc, CS_BINARY);760if (tracing)761dtEvent("loadDefinition: MUST BE BINARY (no source) " +762c.getName());763bc.loadNested(this);764if (tracing)765dtExit("loadDefinition: EXIT " +766c.getName() + ", status " + c.getStatus());767return;768}769BinaryClass bc = null;770try {771if (srcfile.lastModified() > binfile.lastModified()) {772// must be source, it is newer than the binary773c.setDefinition(null, CS_SOURCE);774if (tracing)775dtEvent("loadDefinition: MUST BE SOURCE (younger than binary) " +776c.getName());777return;778}779bc = loadFile(binfile);780} catch (IOException e) {781error(0, "io.exception", binfile);782if (tracing)783dtEvent("loadDefinition: IO EXCEPTION (binary)");784}785if ((bc != null) && !bc.getName().equals(nm)) {786error(0, "wrong.class", binfile.getPath(), c, bc);787bc = null;788if (tracing)789dtEvent("loadDefinition: WRONG CLASS (binary)");790}791if (bc != null) {792Identifier name = bc.getName();793if (name.equals(c.getName())) {794if (dependencies()) {795c.setDefinition(bc, CS_UNDECIDED);796if (tracing)797dtEvent("loadDefinition: UNDECIDED " + name);798} else {799c.setDefinition(bc, CS_BINARY);800if (tracing)801dtEvent("loadDefinition: MUST BE BINARY " + name);802}803} else {804c.setDefinition(null, CS_NOTFOUND);805if (tracing)806dtEvent("loadDefinition: NOT FOUND (source or binary)");807if (dependencies()) {808getClassDeclaration(name).setDefinition(bc, CS_UNDECIDED);809if (tracing)810dtEvent("loadDefinition: UNDECIDED " + name);811} else {812getClassDeclaration(name).setDefinition(bc, CS_BINARY);813if (tracing)814dtEvent("loadDefinition: MUST BE BINARY " + name);815}816}817} else {818c.setDefinition(null, CS_NOTFOUND);819if (tracing)820dtEvent("loadDefinition: NOT FOUND (source or binary)");821}822if (bc != null && bc == c.getClassDefinition())823bc.loadNested(this);824if (tracing) dtExit("loadDefinition: EXIT " +825c.getName() + ", status " + c.getStatus());826return;827}828829case CS_UNDECIDED: {830if (tracing) dtEvent("loadDefinition: STATUS IS UNDECIDED");831Hashtable tab = new Hashtable();832if (!needsCompilation(tab, c)) {833// All undecided classes that this class depends on must be binary834for (Enumeration e = tab.keys() ; e.hasMoreElements() ; ) {835ClassDeclaration dep = (ClassDeclaration)e.nextElement();836if (dep.getStatus() == CS_UNDECIDED) {837// must be binary, dependencies need compilation838dep.setDefinition(dep.getClassDefinition(), CS_BINARY);839if (tracing)840dtEvent("loadDefinition: MUST BE BINARY " + dep);841}842}843}844if (tracing) dtExit("loadDefinition: EXIT " +845c.getName() + ", status " + c.getStatus());846return;847}848849case CS_SOURCE: {850if (tracing) dtEvent("loadDefinition: STATUS IS SOURCE");851ClassFile srcfile = null;852Package pkg = null;853if (c.getClassDefinition() != null) {854// Use the source file name from the binary class file855try {856pkg = getPackage(c.getName().getQualifier());857srcfile = pkg.getSourceFile((String)c.getClassDefinition().getSource());858} catch (IOException e) {859error(0, "io.exception", c);860if (tracing)861dtEvent("loadDefinition: IO EXCEPTION (package)");862}863if (srcfile == null) {864String fn = (String)c.getClassDefinition().getSource();865srcfile = new ClassFile(new File(fn));866}867} else {868// Get a source file name from the package869Identifier nm = c.getName();870try {871pkg = getPackage(nm.getQualifier());872srcfile = pkg.getSourceFile(nm.getName());873} catch (IOException e) {874error(0, "io.exception", c);875if (tracing)876dtEvent("loadDefinition: IO EXCEPTION (package)");877}878if (srcfile == null) {879// not found, there is no source880c.setDefinition(null, CS_NOTFOUND);881if (tracing)882dtExit("loadDefinition: SOURCE NOT FOUND " +883c.getName() + ", status " + c.getStatus());884return;885}886}887try {888parseFile(srcfile);889} catch (FileNotFoundException e) {890error(0, "io.exception", srcfile);891if (tracing) dtEvent("loadDefinition: IO EXCEPTION (source)");892}893if ((c.getClassDefinition() == null) || (c.getStatus() == CS_SOURCE)) {894// not found after parsing the file895error(0, "wrong.source", srcfile.getPath(), c, pkg);896c.setDefinition(null, CS_NOTFOUND);897if (tracing)898dtEvent("loadDefinition: WRONG CLASS (source) " +899c.getName());900}901if (tracing) dtExit("loadDefinition: EXIT " +902c.getName() + ", status " + c.getStatus());903return;904}905}906if (tracing) dtExit("loadDefinition: EXIT " +907c.getName() + ", status " + c.getStatus());908}909910/**911* Create a new class.912*/913public ClassDefinition makeClassDefinition(Environment toplevelEnv,914long where,915IdentifierToken name,916String doc, int modifiers,917IdentifierToken superClass,918IdentifierToken interfaces[],919ClassDefinition outerClass) {920921Identifier nm = name.getName();922long nmpos = name.getWhere();923924Identifier pkgNm;925String mangledName = null;926ClassDefinition localContextClass = null;927928// Provide name for a local class. This used to be set after929// the class was created, but it is needed for checking within930// the class constructor.931// NOTE: It seems that we could always provide the simple name,932// and thereby avoid the test in 'ClassDefinition.getLocalName()'933// for the definedness of the local name. There, if the local934// name is not set, a simple name is extracted from the result of935// 'getName()'. That name can potentially change, however, as936// it is ultimately derived from 'ClassType.className', which is937// set by 'Type.changeClassName'. Better leave this alone...938Identifier localName = null;939940if (nm.isQualified() || nm.isInner()) {941pkgNm = nm;942} else if ((modifiers & (M_LOCAL | M_ANONYMOUS)) != 0) {943// Inaccessible class. Create a name of the form944// 'PackageMember.N$localName' or 'PackageMember.N'.945// Note that the '.' will be converted later to a '$'.946// pkgNm = generateName(outerClass, nm);947localContextClass = outerClass.getTopClass();948// Always use the smallest number in generating the name that949// renders the complete name unique within the top-level class.950// This is required to make the names more predictable, as part951// of a serialization-related workaround, and satisfies an obscure952// requirement that the name of a local class be of the form953// 'PackageMember$1$localName' when this name is unique.954for (int i = 1 ; ; i++) {955mangledName = i + (nm.equals(idNull) ? "" : SIG_INNERCLASS + nm);956if (localContextClass.getLocalClass(mangledName) == null) {957break;958}959}960Identifier outerNm = localContextClass.getName();961pkgNm = Identifier.lookupInner(outerNm, Identifier.lookup(mangledName));962//System.out.println("LOCAL CLASS: " + pkgNm + " IN " + localContextClass);963if ((modifiers & M_ANONYMOUS) != 0) {964localName = idNull;965} else {966// Local class has a locally-scoped name which is independent of pkgNm.967localName = nm;968}969} else if (outerClass != null) {970// Accessible inner class. Qualify name with surrounding class name.971pkgNm = Identifier.lookupInner(outerClass.getName(), nm);972} else {973pkgNm = nm;974}975976// Find the class977ClassDeclaration c = toplevelEnv.getClassDeclaration(pkgNm);978979// Make sure this is the first definition980if (c.isDefined()) {981toplevelEnv.error(nmpos, "class.multidef",982c.getName(), c.getClassDefinition().getSource());983// Don't mess with the existing class declarations with same name984c = new ClassDeclaration (pkgNm);985}986987if (superClass == null && !pkgNm.equals(idJavaLangObject)) {988superClass = new IdentifierToken(idJavaLangObject);989}990991ClassDefinition sourceClass =992new SourceClass(toplevelEnv, where, c, doc,993modifiers, superClass, interfaces,994(SourceClass) outerClass, localName);995996if (outerClass != null) {997// It is a member of its enclosing class.998outerClass.addMember(toplevelEnv, new SourceMember(sourceClass));999// Record local (or anonymous) class in the class whose name will1000// serve as the prefix of the local class name. This is necessary1001// so that the class may be retrieved from its name, which does not1002// fully represent the class nesting structure.1003// See 'ClassDefinition.getClassDefinition'.1004// This is part of a fix for bugid 4054523 and 4030421.1005if ((modifiers & (M_LOCAL | M_ANONYMOUS)) != 0) {1006localContextClass.addLocalClass(sourceClass, mangledName);1007}1008}10091010// The local name of an anonymous or local class used to be set here1011// with a call to 'setLocalName'. This has been moved to the constructor1012// for 'SourceClass', which now takes a 'localName' argument.10131014return sourceClass;1015}10161017/**1018* Create a new field.1019*/1020public MemberDefinition makeMemberDefinition(Environment origEnv, long where,1021ClassDefinition clazz,1022String doc, int modifiers,1023Type type, Identifier name,1024IdentifierToken argNames[],1025IdentifierToken expIds[],1026Object value) {1027if (tracing) dtEvent("makeMemberDefinition: " + name + " IN " + clazz);1028Vector v = null;1029if (argNames != null) {1030v = new Vector(argNames.length);1031for (int i = 0 ; i < argNames.length ; i++) {1032v.addElement(argNames[i]);1033}1034}1035SourceMember f = new SourceMember(where, clazz, doc, modifiers,1036type, name, v, expIds, (Node)value);1037clazz.addMember(origEnv, f);1038return f;1039}10401041/**1042* Release resources in classpath.1043*/1044public void shutdown() {1045try {1046if (sourcePath != null) {1047sourcePath.close();1048}1049if (binaryPath != null && binaryPath != sourcePath) {1050binaryPath.close();1051}1052} catch (IOException ee) {1053output(Main.getText("benv.failed_to_close_class_path",1054ee.toString()));1055}1056sourcePath = null;1057binaryPath = null;10581059super.shutdown();1060}10611062/**1063* Error String1064*/1065public1066String errorString(String err, Object arg1, Object arg2, Object arg3) {1067String key = null;10681069if(err.startsWith("warn."))1070key = "javac.err." + err.substring(5);1071else1072key = "javac.err." + err;10731074return Main.getText(key,1075arg1 != null ? arg1.toString() : null,1076arg2 != null ? arg2.toString() : null,1077arg3 != null ? arg3.toString() : null);1078}10791080/**1081* The filename where the last errors have occurred1082*/1083String errorFileName;10841085/**1086* List of outstanding error messages1087*/1088ErrorMessage errors;10891090/**1091* Insert an error message in the list of outstanding error messages.1092* The list is sorted on input position and contains no duplicates.1093* The return value indicates whether or not the message was1094* actually inserted.1095*1096* The method flushErrors() used to check for duplicate error messages.1097* It would only detect duplicates if they were contiguous. Removing1098* non-contiguous duplicate error messages is slightly less complicated1099* at insertion time, so the functionality was moved here. This also1100* saves a miniscule number of allocations.1101*/1102protected1103boolean insertError(long where, String message) {1104//output("ERR = " + message);11051106if (errors == null1107|| errors.where > where) {1108// If the list is empty, or the error comes before any other1109// errors, insert it at the beginning of the list.1110ErrorMessage newMsg = new ErrorMessage(where, message);1111newMsg.next = errors;1112errors = newMsg;11131114} else if (errors.where == where1115&& errors.message.equals(message)) {1116// The new message is an exact duplicate of the first message1117// in the list. Don't insert it.1118return false;11191120} else {1121// Okay, we know that the error doesn't come first. Walk1122// the list until we find the right position for insertion.1123ErrorMessage current = errors;1124ErrorMessage next;11251126while ((next = current.next) != null1127&& next.where < where) {1128current = next;1129}11301131// Now walk over any errors with the same location, looking1132// for duplicates. If we find a duplicate, don't insert the1133// error.1134while ((next = current.next) != null1135&& next.where == where) {1136if (next.message.equals(message)) {1137// We have found an exact duplicate. Don't bother to1138// insert the error.1139return false;1140}1141current = next;1142}11431144// Now insert after current.1145ErrorMessage newMsg = new ErrorMessage(where, message);1146newMsg.next = current.next;1147current.next = newMsg;1148}11491150// Indicate that the insertion occurred.1151return true;1152}11531154private int errorsPushed;11551156/**1157* Maximum number of errors to print.1158*/1159public int errorLimit = 100;11601161private boolean hitErrorLimit;11621163/**1164* Flush outstanding errors1165*/11661167public void pushError(String errorFileName, int line, String message,1168String referenceText, String referenceTextPointer) {1169int limit = errorLimit + nwarnings;1170if (++errorsPushed >= limit && errorLimit >= 0) {1171if (!hitErrorLimit) {1172hitErrorLimit = true;1173output(errorString("too.many.errors",1174new Integer(errorLimit),null,null));1175}1176return;1177}1178if (errorFileName.endsWith(".java")) {1179output(errorFileName + ":" + line + ": " + message);1180output(referenceText);1181output(referenceTextPointer);1182} else {1183// It wasn't really a source file (probably an error or1184// warning because of a malformed or badly versioned1185// class file.1186output(errorFileName + ": " + message);1187}1188}11891190public void flushErrors() {1191if (errors == null) {1192return;1193}11941195boolean inputAvail = false;1196// Read the file1197char data[] = null;1198int dataLength = 0;1199// A malformed file encoding could cause a CharConversionException.1200// If something bad happens while trying to find the source file,1201// don't bother trying to show lines.1202try {1203FileInputStream in = new FileInputStream(errorFileName);1204data = new char[in.available()];1205InputStreamReader reader =1206(getCharacterEncoding() != null ?1207new InputStreamReader(in, getCharacterEncoding()) :1208new InputStreamReader(in));1209dataLength = reader.read(data);1210reader.close();1211inputAvail = true;1212} catch(IOException e) {1213// inputAvail will not be set1214}12151216// Report the errors1217for (ErrorMessage msg = errors ; msg != null ; msg = msg.next) {1218// There used to be code here which checked1219// for duplicate error messages. This functionality1220// has been moved to the method insertError(). See1221// the comments on that method for more information.12221223int ln = (int) (msg.where >>> WHEREOFFSETBITS);1224int off = (int) (msg.where & ((1L << WHEREOFFSETBITS) - 1));1225if (off > dataLength) off = dataLength;12261227String referenceString = "";1228String markerString = "";1229if(inputAvail) {1230int i, j;1231for (i = off ; (i > 0) && (data[i - 1] != '\n') && (data[i - 1] != '\r') ; i--);1232for (j = off ; (j < dataLength) && (data[j] != '\n') && (data[j] != '\r') ; j++);1233referenceString = new String(data, i, j - i);12341235char strdata[] = new char[(off - i) + 1];1236for (j = i ; j < off ; j++) {1237strdata[j-i] = (data[j] == '\t') ? '\t' : ' ';1238}1239strdata[off-i] = '^';1240markerString = new String(strdata);1241}12421243errorConsumer.pushError(errorFileName, ln, msg.message,1244referenceString, markerString);1245}1246errors = null;1247}12481249/**1250* Report error1251*/1252public1253void reportError(Object src, long where, String err, String msg) {1254if (src == null) {1255if (errorFileName != null) {1256flushErrors();1257errorFileName = null;1258}1259if (err.startsWith("warn.")) {1260if (warnings()) {1261nwarnings++;1262output(msg);1263}1264return;1265}1266output("error: " + msg);1267nerrors++;1268flags |= F_ERRORSREPORTED;12691270} else if (src instanceof String) {1271String fileName = (String)src;12721273// Flush errors if we've moved on to a new file.1274if (!fileName.equals(errorFileName)) {1275flushErrors();1276errorFileName = fileName;1277}12781279// Classify `err' as a warning, deprecation warning, or1280// error message. Proceed accordingly.1281if (err.startsWith("warn.")) {1282if (err.indexOf("is.deprecated") >= 0) {1283// This is a deprecation warning. Add `src' to the1284// list of files with deprecation warnings.1285if (!deprecationFiles.contains(src)) {1286deprecationFiles.addElement(src);1287}12881289// If we are reporting deprecations, try to add it1290// to our list. Otherwise, just increment the1291// deprecation count.1292if (deprecation()) {1293if (insertError(where, msg)) {1294ndeprecations++;1295}1296} else {1297ndeprecations++;1298}1299} else {1300// This is a regular warning. If we are reporting1301// warnings, try to add it to the list. Otherwise, just1302// increment the warning count.1303if (warnings()) {1304if (insertError(where, msg)) {1305nwarnings++;1306}1307} else {1308nwarnings++;1309}1310}1311} else {1312// This is an error. Try to add it to the list of errors.1313// If it isn't a duplicate, increment our error count.1314if (insertError(where, msg)) {1315nerrors++;1316flags |= F_ERRORSREPORTED;1317}1318}1319} else if (src instanceof ClassFile) {1320reportError(((ClassFile)src).getPath(), where, err, msg);13211322} else if (src instanceof Identifier) {1323reportError(src.toString(), where, err, msg);13241325} else if (src instanceof ClassDeclaration) {1326try {1327reportError(((ClassDeclaration)src).getClassDefinition(this), where, err, msg);1328} catch (ClassNotFound e) {1329reportError(((ClassDeclaration)src).getName(), where, err, msg);1330}1331} else if (src instanceof ClassDefinition) {1332ClassDefinition c = (ClassDefinition)src;1333if (!err.startsWith("warn.")) {1334c.setError();1335}1336reportError(c.getSource(), where, err, msg);13371338} else if (src instanceof MemberDefinition) {1339reportError(((MemberDefinition)src).getClassDeclaration(), where, err, msg);13401341} else {1342output(src + ":error=" + err + ":" + msg);1343}1344}13451346/**1347* Issue an error1348*/1349public void error(Object source, long where, String err, Object arg1, Object arg2, Object arg3) {1350if (errorsPushed >= errorLimit + nwarnings) {1351// Don't bother to queue any more errors if they won't get printed.1352return;1353}1354if (System.getProperty("javac.dump.stack") != null) {1355output("javac.err."+err+": "+errorString(err, arg1, arg2, arg3));1356new Exception("Stack trace").printStackTrace(new PrintStream(out));1357}1358reportError(source, where, err, errorString(err, arg1, arg2, arg3));1359}13601361/**1362* Output a string. This can either be an error message or something1363* for debugging.1364*/1365public void output(String msg) {1366PrintStream out =1367this.out instanceof PrintStream ? (PrintStream)this.out1368: new PrintStream(this.out, true);1369out.println(msg);1370}1371}137213731374