/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/**
* Main environment of the batch version of the Java compiler,
* this needs more work.
*
* WARNING: The contents of this source file are not part of any
* supported API. Code that depends on them does so at its own risk:
* they are subject to change or removal without notice.
*/
public
/**
* The stream where error message are printed.
*/
/**
* The path we use for finding source files.
*/
/**
* The path we use for finding class (binary) files.
*/
/**
* A hashtable of resource contexts.
*/
/**
* The classes, in order of appearance.
*/
/**
* The classes, keyed by ClassDeclaration.
*/
/**
* flags
*/
public int flags;
/**
* Major and minor versions to use for generated class files.
* Environments that extend BatchEnvironment (such as javadoc's
* Env class) get the default values below.
*
* javac itself may override these versions with values determined
* from the command line "-target" option.
*/
// JCOV
/**
* coverage data file
*/
// end JCOV
/**
* The number of errors and warnings
*/
public int nerrors;
public int nwarnings;
public int ndeprecations;
/**
* A list of files containing deprecation warnings.
*/
/**
* writes out error messages
*/
/**
* Old constructors -- these constructors build a BatchEnvironment
* with an old-style class path.
*/
}
}
}
/**
* New constructors -- these constructors build a BatchEnvironment
* with a source path and a binary path.
*/
}
}
this.sourcePath = sourcePath;
this.binaryPath = binaryPath;
}
/**
* Factory
*/
}
// Create our source classpath and our binary classpath
if (classPathString == null) {
// The env.class.path property is the user's CLASSPATH
// environment variable, and it set by the wrapper (ie,
// javac.exe).
if (classPathString == null) {
classPathString = ".";
}
}
if (srcPathString == null) {
}
if (sysClassPathString == null) {
}
}
if (extDirsString == null) {
}
if (extDirsString != null) {
while (st.hasMoreTokens()) {
}
if (dir.isDirectory()) {
}
}
}
}
}
}
}
}
}
/**
* Return flags
*/
public int getFlags() {
return flags;
}
/**
* Return major version to use for generated class files
*/
public short getMajorVersion() {
return majorVersion;
}
/**
* Return minor version to use for generated class files
*/
public short getMinorVersion() {
return minorVersion;
}
// JCOV
/**
* Return coverage data file
*/
return covFile;
}
// end JCOV
/**
* Return an enumeration of all the currently defined classes
* in order of appearance to getClassDeclaration().
*/
return classesOrdered.elements();
}
/**
* A set of Identifiers for all packages exempt from the "exists"
* check in Imports#resolve(). These are the current packages for
* all classes being compiled as of the first call to isExemptPackage.
*/
/**
* Tells whether an Identifier refers to a package which should be
* exempt from the "exists" check in Imports#resolve().
*/
if (exemptPackages == null) {
// Collect a list of the packages of all classes currently
// being compiled.
}
}
/**
* Set the set of packages which are exempt from the exists check
* in Imports#resolve().
*/
private void setExemptPackages() {
// The JLS gives us the freedom to define "accessibility" of
// a package in whatever manner we wish. After the evaluation
// of bug 4093217, we have decided to consider a package P
// accessible if either:
//
// 1. The directory corresponding to P exists on the classpath.
// 2. For any class C currently being compiled, C belongs to
// package P.
// 3. For any class C currently being compiled, C belongs to
// package Q and Q is a subpackage of P.
//
// In order to implement this, we collect the current packages
// (and prefixes) of all packages we have found so far. These
// will be exempt from the "exists" check in
// sun.tools.java.Imports#resolve().
// Add all of the current packages and their prefixes to our set.
continue;
// Add the name of this package and all of its prefixes
// to our set.
}
}
}
// Before we go any further, we make sure java.lang is
// accessible and that it is not ambiguous. These checks
// are performed for "ordinary" packages in
// sun.tools.java.Imports#resolve(). The reason we perform
// them specially for java.lang is that we want to report
// the error once, and outside of any particular file.
// Check to see if java.lang is accessible.
// Add java.lang to the set of exempt packages.
try {
// java.lang doesn't exist.
return;
}
} catch (IOException ee) {
// We got an IO exception checking to see if the package
// java.lang exists.
}
}
// Next we ensure that java.lang is not both a class and
// a package. (Fix for 4101529)
//
// This change has been backed out because, on WIN32, it
// failed to take character case into account. It will
// be put back in later.
//
// Identifier resolvedName =
// resolvePackageQualifiedName(idJavaLang);
// Identifier topClassName = resolvedName.getTopName();
// //if (Imports.importable(topClassName, env)) {
// if (Imports.importable(topClassName, this)) {
// // It is a package and a class. Emit the error.
// error(0, "package.class.conflict.strong",
// idJavaLang, topClassName);
// return;
// }
}
/**
* Get a class, given the fully qualified class name
*/
}
if (c == null) {
}
return c;
}
/**
* Check if a class exists
* Applies only to package members (non-nested classes).
*/
}
try {
} catch (IOException e) {
return true;
}
}
/**
* Generate a new name similar to the given one.
* Do it in such a way that repeated compilations of
* the same source generate the same series of names.
*/
// This code does not perform as stated above.
// Correction below is part of fix for bug id 4056065.
//
// NOTE: The method 'generateName' has now been folded into its
// single caller, 'makeClassDefinition', which appears later in
// this file.
/*--------------------------*
public Identifier generateName(ClassDefinition outerClass, Identifier nm) {
Identifier outerNm = outerClass.getName();
Identifier flat = outerNm.getFlatName();
Identifier stem = Identifier.lookup(outerNm.getQualifier(),
flat.getHead());
for (int i = 1; ; i++) {
String name = i + (nm.equals(idNull) ? "" : SIG_INNERCLASS + nm);
Identifier nm1 = Identifier.lookupInner(stem,
Identifier.lookup(name));
if (classes.get(Type.tClass(nm1)) == null)
return nm1;
}
}
*--------------------------*/
/**
* Get the package path for a package
*/
if (p == null) {
}
return p;
}
/**
* Parse a source file
*/
BatchParser p;
try {
// p = new BatchParser(e, new BufferedInputStream(input));
} catch(IOException ex) {
throw new FileNotFoundException();
}
try {
p.parseFile();
} catch(Exception e) {
throw new CompilerError(e);
}
try {
} catch (IOException ex) {
// We're turn with the input, so ignore this.
}
if (verbose()) {
}
// The JLS allows a file to contain no compilation units --
// that is, it allows a file to contain no classes or interfaces.
// In this case, we are still responsible for checking that the
// imports resolve properly. The way the compiler is organized,
// this is the last point at which we still have enough information
// to do so. (Fix for 4041851).
} else {
// In an attempt to see that classes which come from the
// same source file are all recompiled when any one of them
// would be recompiled (when using the -depend option) we
// introduce artificial dependencies between these classes.
// We do this by calling the addDependency() method, which
// adds a (potentially unused) class reference to the constant
// pool of the class.
//
// Previously, we added a dependency from every class in the
// file, to every class in the file. This introduced, in
// total, a quadratic number of potentially bogus constant
// pool entries. This was bad. Now we add our artificial
// dependencies in such a way that the classes are connected
// in a circle. While single links is probably sufficient, the
// code below adds double links just to be diligent.
// (Fix for 4108286).
//
// Note that we don't chain in inner classes. The links
// between them and their outerclass should be sufficient
// here.
// (Fix for 4107960).
//
// The dependency code was previously in BatchParser.java.
// first will not be an inner class.
if (first.isInnerClass()) {
throw new CompilerError("BatchEnvironment, first is inner");
}
while (e.hasMoreElements()) {
// Don't chain in inner classes.
if (next.isInnerClass()) {
continue;
}
}
// Make a circle. Don't bother to add a dependency if there
// is only one class in the file.
}
}
}
/**
* Load a binary file
*/
BinaryClass c = null;
try {
loadFileFlags());
} catch (ClassFormatError e) {
return null;
// If we get an EOF while processing a class file, then
// it has been truncated. We let other I/O errors pass
// through. Fix for 4088443.
return null;
}
if (verbose()) {
}
return c;
}
/**
* Default flags for loadFile. Subclasses may override this.
*/
int loadFileFlags() {
return 0;
}
/**
* Load a binary class
*/
switch (c.getStatus()) {
case CS_UNDEFINED:
loadDefinition(c);
return needsCompilation(check, c);
case CS_UNDECIDED:
// It must be source, dependencies need compilation
return true;
}
}
}
return false;
case CS_BINARY:
if (tracing) {
}
return false;
}
return true;
}
/**
* Load the definition of a class
* or at least determine how to load it.
* The caller must repeat calls to this method
* until it the state converges to CS_BINARY, CS_PARSED, or the like..
* @see ClassDeclaration#getClassDefinition
*/
switch (c.getStatus()) {
case CS_UNDEFINED: {
if (tracing)
dtEvent("loadDefinition: STATUS IS UNDEFINED");
try {
} catch (IOException e) {
// If we can't get at the package, then we'll just
// have to set the class to be not found.
if (tracing)
dtExit("loadDefinition: IO EXCEPTION (package)");
return;
}
// must be source, there is no binary
if (tracing)
dtExit("loadDefinition: MUST BE SOURCE (no binary) " +
c.getName());
return;
}
if (tracing)
try {
} catch (IOException e) {
// If we can't access the binary, set the class to
// be not found. (bug id 4030497)
if (tracing)
dtExit("loadDefinition: IO EXCEPTION (binary)");
return;
}
if (tracing)
dtEvent("loadDefinition: WRONG CLASS (binary)");
}
// no source nor binary found
if (tracing)
dtExit("loadDefinition: NOT FOUND (source or binary)");
return;
}
// Couldn't find the source, try the one mentioned in the binary
// Look for the source file
if (tracing)
dtEvent("loadDefinition: FILENAME IN BINARY " +
srcfile);
// must be source, it is newer than the binary
if (tracing)
dtEvent("loadDefinition: SOURCE IS NEWER " +
srcfile);
bc.loadNested(this);
if (tracing)
dtExit("loadDefinition: MUST BE SOURCE " +
c.getName());
return;
}
if (dependencies()) {
if (tracing)
dtEvent("loadDefinition: UNDECIDED " +
c.getName());
} else {
if (tracing)
dtEvent("loadDefinition: MUST BE BINARY " +
c.getName());
}
bc.loadNested(this);
if (tracing)
dtExit("loadDefinition: EXIT " +
return;
}
}
// It must be binary, there is no source
if (tracing)
dtEvent("loadDefinition: MUST BE BINARY (no source) " +
c.getName());
bc.loadNested(this);
if (tracing)
dtExit("loadDefinition: EXIT " +
return;
}
try {
// must be source, it is newer than the binary
if (tracing)
dtEvent("loadDefinition: MUST BE SOURCE (younger than binary) " +
c.getName());
return;
}
} catch (IOException e) {
if (tracing)
dtEvent("loadDefinition: IO EXCEPTION (binary)");
}
if (tracing)
dtEvent("loadDefinition: WRONG CLASS (binary)");
}
if (dependencies()) {
if (tracing)
} else {
if (tracing)
}
} else {
if (tracing)
dtEvent("loadDefinition: NOT FOUND (source or binary)");
if (dependencies()) {
if (tracing)
} else {
if (tracing)
}
}
} else {
if (tracing)
dtEvent("loadDefinition: NOT FOUND (source or binary)");
}
bc.loadNested(this);
return;
}
case CS_UNDECIDED: {
if (!needsCompilation(tab, c)) {
// All undecided classes that this class depends on must be binary
// must be binary, dependencies need compilation
if (tracing)
}
}
}
return;
}
case CS_SOURCE: {
if (c.getClassDefinition() != null) {
// Use the source file name from the binary class file
try {
} catch (IOException e) {
if (tracing)
dtEvent("loadDefinition: IO EXCEPTION (package)");
}
}
} else {
// Get a source file name from the package
try {
} catch (IOException e) {
if (tracing)
dtEvent("loadDefinition: IO EXCEPTION (package)");
}
// not found, there is no source
if (tracing)
dtExit("loadDefinition: SOURCE NOT FOUND " +
return;
}
}
try {
} catch (FileNotFoundException e) {
}
// not found after parsing the file
if (tracing)
dtEvent("loadDefinition: WRONG CLASS (source) " +
c.getName());
}
return;
}
}
}
/**
* Create a new class.
*/
long where,
// Provide name for a local class. This used to be set after
// the class was created, but it is needed for checking within
// the class constructor.
// NOTE: It seems that we could always provide the simple name,
// and thereby avoid the test in 'ClassDefinition.getLocalName()'
// for the definedness of the local name. There, if the local
// name is not set, a simple name is extracted from the result of
// 'getName()'. That name can potentially change, however, as
// it is ultimately derived from 'ClassType.className', which is
// set by 'Type.changeClassName'. Better leave this alone...
// Inaccessible class. Create a name of the form
// 'PackageMember.N$localName' or 'PackageMember.N'.
// Note that the '.' will be converted later to a '$'.
// pkgNm = generateName(outerClass, nm);
// Always use the smallest number in generating the name that
// renders the complete name unique within the top-level class.
// This is required to make the names more predictable, as part
// of a serialization-related workaround, and satisfies an obscure
// requirement that the name of a local class be of the form
// 'PackageMember$1$localName' when this name is unique.
for (int i = 1 ; ; i++) {
break;
}
}
//System.out.println("LOCAL CLASS: " + pkgNm + " IN " + localContextClass);
} else {
// Local class has a locally-scoped name which is independent of pkgNm.
}
} else if (outerClass != null) {
// Accessible inner class. Qualify name with surrounding class name.
} else {
}
// Find the class
// Make sure this is the first definition
if (c.isDefined()) {
// Don't mess with the existing class declarations with same name
c = new ClassDeclaration (pkgNm);
}
}
if (outerClass != null) {
// It is a member of its enclosing class.
// Record local (or anonymous) class in the class whose name will
// serve as the prefix of the local class name. This is necessary
// so that the class may be retrieved from its name, which does not
// fully represent the class nesting structure.
// See 'ClassDefinition.getClassDefinition'.
// This is part of a fix for bugid 4054523 and 4030421.
}
}
// The local name of an anonymous or local class used to be set here
// with a call to 'setLocalName'. This has been moved to the constructor
// for 'SourceClass', which now takes a 'localName' argument.
return sourceClass;
}
/**
* Create a new field.
*/
v.addElement(argNames[i]);
}
}
return f;
}
/**
* Release resources in classpath.
*/
public void shutdown() {
try {
if (sourcePath != null) {
sourcePath.close();
}
binaryPath.close();
}
} catch (IOException ee) {
}
sourcePath = null;
binaryPath = null;
super.shutdown();
}
/**
* Error String
*/
public
else
}
/**
* The filename where the last errors have occurred
*/
/**
* List of outstanding error messages
*/
/**
* Insert an error message in the list of outstanding error messages.
* The list is sorted on input position and contains no duplicates.
* The return value indicates whether or not the message was
* actually inserted.
*
* The method flushErrors() used to check for duplicate error messages.
* It would only detect duplicates if they were contiguous. Removing
* non-contiguous duplicate error messages is slightly less complicated
* at insertion time, so the functionality was moved here. This also
* saves a miniscule number of allocations.
*/
protected
//output("ERR = " + message);
// If the list is empty, or the error comes before any other
// errors, insert it at the beginning of the list.
// The new message is an exact duplicate of the first message
// in the list. Don't insert it.
return false;
} else {
// Okay, we know that the error doesn't come first. Walk
// the list until we find the right position for insertion.
}
// Now walk over any errors with the same location, looking
// for duplicates. If we find a duplicate, don't insert the
// error.
// We have found an exact duplicate. Don't bother to
// insert the error.
return false;
}
}
// Now insert after current.
}
// Indicate that the insertion occurred.
return true;
}
private int errorsPushed;
/**
* Maximum number of errors to print.
*/
private boolean hitErrorLimit;
/**
* Flush outstanding errors
*/
if (!hitErrorLimit) {
hitErrorLimit = true;
}
return;
}
} else {
// It wasn't really a source file (probably an error or
// warning because of a malformed or badly versioned
// class file.
}
}
public void flushErrors() {
return;
}
boolean inputAvail = false;
// Read the file
int dataLength = 0;
// A malformed file encoding could cause a CharConversionException.
// If something bad happens while trying to find the source file,
// don't bother trying to show lines.
try {
(getCharacterEncoding() != null ?
new InputStreamReader(in));
inputAvail = true;
} catch(IOException e) {
// inputAvail will not be set
}
// Report the errors
// There used to be code here which checked
// for duplicate error messages. This functionality
// has been moved to the method insertError(). See
// the comments on that method for more information.
if(inputAvail) {
int i, j;
for (j = i ; j < off ; j++) {
}
}
}
}
/**
* Report error
*/
public
if (errorFileName != null) {
flushErrors();
}
if (warnings()) {
nwarnings++;
}
return;
}
nerrors++;
// Flush errors if we've moved on to a new file.
flushErrors();
}
// Classify `err' as a warning, deprecation warning, or
// error message. Proceed accordingly.
// This is a deprecation warning. Add `src' to the
// list of files with deprecation warnings.
}
// If we are reporting deprecations, try to add it
// to our list. Otherwise, just increment the
// deprecation count.
if (deprecation()) {
}
} else {
}
} else {
// This is a regular warning. If we are reporting
// warnings, try to add it to the list. Otherwise, just
// increment the warning count.
if (warnings()) {
nwarnings++;
}
} else {
nwarnings++;
}
}
} else {
// This is an error. Try to add it to the list of errors.
// If it isn't a duplicate, increment our error count.
nerrors++;
}
}
} else if (src instanceof Identifier) {
} else if (src instanceof ClassDeclaration) {
try {
} catch (ClassNotFound e) {
}
} else if (src instanceof ClassDefinition) {
c.setError();
}
} else if (src instanceof MemberDefinition) {
} else {
}
}
/**
* Issue an error
*/
// Don't bother to queue any more errors if they won't get printed.
return;
}
}
}
/**
* Output a string. This can either be an error message or something
* for debugging.
*/
: new PrintStream(this.out, true);
}
}