Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/sun/tools/java/Environment.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.Stack;28import java.io.IOException;29import sun.tools.tree.Context;30//JCOV31import java.io.File;32//end JCOV3334/**35* This class defines the environment for a compilation.36* It is used to load classes, resolve class names and37* report errors. It is an abstract class, a subclass38* must define implementations for some of the functions.<p>39*40* An environment has a source object associated with it.41* This is the thing against which errors are reported, it42* is usually a file name, a field or a class.<p>43*44* Environments can be nested to change the source object.<p>45*46* WARNING: The contents of this source file are not part of any47* supported API. Code that depends on them does so at its own risk:48* they are subject to change or removal without notice.49*50* @author Arthur van Hoff51*/5253public class Environment implements Constants {54/**55* The actual environment to which everything is forwarded.56*/57Environment env;5859/**60* External character encoding name61*/62String encoding;6364/**65* The object that is currently being parsed/compiled.66* It is either a file name (String) or a field (MemberDefinition)67* or a class (ClassDeclaration or ClassDefinition).68*/69Object source;7071public Environment(Environment env, Object source) {72if (env != null && env.env != null && env.getClass() == this.getClass())73env = env.env; // a small optimization74this.env = env;75this.source = source;76}77public Environment() {78this(null, null);79}8081/**82* Tells whether an Identifier refers to a package which should be83* exempt from the "exists" check in Imports#resolve().84*/85public boolean isExemptPackage(Identifier id) {86return env.isExemptPackage(id);87}8889/**90* Return a class declaration given a fully qualified class name.91*/92public ClassDeclaration getClassDeclaration(Identifier nm) {93return env.getClassDeclaration(nm);94}9596/**97* Return a class definition given a fully qualified class name.98* <p>99* Should be called only with 'internal' class names, i.e., the result100* of a call to 'resolveName' or a synthetic class name.101*/102public final ClassDefinition getClassDefinition(Identifier nm) throws ClassNotFound {103if (nm.isInner()) {104ClassDefinition c = getClassDefinition(nm.getTopName());105Identifier tail = nm.getFlatName();106walkTail:107while (tail.isQualified()) {108tail = tail.getTail();109Identifier head = tail.getHead();110//System.out.println("CLASS: " + c + " HEAD: " + head + " TAIL: " + tail);111String hname = head.toString();112// If the name is of the form 'ClassName.N$localName', where N is113// a number, the field 'N$localName' may not necessarily be a member114// of the class named by 'ClassName', but might be a member of some115// inaccessible class contained within it. We use 'getLocalClass'116// to do the lookup in this case. This is part of a fix for bugid117// 4054523 and 4030421. See also 'BatchEnvironment.makeClassDefinition'.118// This should also work for anonymous class names of the form119// 'ClassName.N'. Note that the '.' qualifications get converted to120// '$' characters when determining the external name of the class and121// the name of the class file.122if (hname.length() > 0123&& Character.isDigit(hname.charAt(0))) {124ClassDefinition localClass = c.getLocalClass(hname);125if (localClass != null) {126c = localClass;127continue walkTail;128}129} else {130for (MemberDefinition f = c.getFirstMatch(head);131f != null; f = f.getNextMatch()) {132if (f.isInnerClass()) {133c = f.getInnerClass();134continue walkTail;135}136}137}138throw new ClassNotFound(Identifier.lookupInner(c.getName(), head));139}140//System.out.println("FOUND " + c + " FOR " + nm);141return c;142}143return getClassDeclaration(nm).getClassDefinition(this);144}145146147/**148* Return a class declaration given a type. Only works for149* class types.150*/151public ClassDeclaration getClassDeclaration(Type t) {152return getClassDeclaration(t.getClassName());153}154155/**156* Return a class definition given a type. Only works for157* class types.158*/159public final ClassDefinition getClassDefinition(Type t) throws ClassNotFound {160return getClassDefinition(t.getClassName());161}162163/**164* Check if a class exists (without actually loading it).165* (Since inner classes cannot in general be examined without166* loading source, this method does not accept inner names.)167*/168public boolean classExists(Identifier nm) {169return env.classExists(nm);170}171172public final boolean classExists(Type t) {173return !t.isType(TC_CLASS) || classExists(t.getClassName());174}175176/**177* Get the package path for a package178*/179public Package getPackage(Identifier pkg) throws IOException {180return env.getPackage(pkg);181}182183/**184* Load the definition of a class.185*/186public void loadDefinition(ClassDeclaration c) {187env.loadDefinition(c);188}189190/**191* Return the source of the environment (ie: the thing being compiled/parsed).192*/193public final Object getSource() {194return source;195}196197/**198* Resolve a type. Make sure that all the classes referred to by199* the type have a definition. Report errors. Return true if200* the type is well-formed. Presently used for types appearing201* in member declarations, which represent named types internally as202* qualified identifiers. Type names appearing in local variable203* declarations and within expressions are represented as identifier204* or field expressions, and are resolved by 'toType', which delegates205* handling of the non-inner portion of the name to this method.206* <p>207* In 'toType', the various stages of qualification are represented by208* separate AST nodes. Here, we are given a single identifier which209* contains the entire qualification structure. It is not possible in210* general to set the error location to the exact position of a component211* that is in error, so an error message must refer to the entire qualified212* name. An attempt to keep track of the string length of the components of213* the name and to offset the location accordingly fails because the initial214* prefix of the name may have been rewritten by an earlier call to215* 'resolveName'. See 'SourceMember.resolveTypeStructure'. The situation216* is actually even worse than this, because only a single location is217* passed in for an entire declaration, which may contain many type names.218* All error messages are thus poorly localized. These checks should be219* done while traversing the parse tree for the type, not the type descriptor.220* <p>221* DESIGN NOTE:222* As far as I can tell, the two-stage resolution of names represented in223* string form is an artifact of the late implementation of inner classes224* and the use of mangled names internally within the compiler. All225* qualified names should have their hiearchical structure made explicit226* in the parse tree at the phase at which they are presented for static227* semantic checking. This would affect class names appearing in 'extends',228* 'implements', and 'throws' clauses, as well as in member declarations.229*/230public boolean resolve(long where, ClassDefinition c, Type t) {231switch (t.getTypeCode()) {232case TC_CLASS: {233ClassDefinition def;234try {235Identifier nm = t.getClassName();236if (!nm.isQualified() && !nm.isInner() && !classExists(nm)) {237resolve(nm); // elicit complaints about ambiguity238}239def = getQualifiedClassDefinition(where, nm, c, false);240if (!c.canAccess(this, def.getClassDeclaration())) {241// Reported error location may be imprecise242// if the name is qualified.243error(where, "cant.access.class", def);244return true; // return false later245}246def.noteUsedBy(c, where, env);247} catch (AmbiguousClass ee) {248error(where, "ambig.class", ee.name1, ee.name2);249return false;250} catch (ClassNotFound e) {251// For now, report "class.and.package" only when the code252// is going to fail anyway.253try {254if (e.name.isInner() &&255getPackage(e.name.getTopName()).exists()) {256env.error(where, "class.and.package",257e.name.getTopName());258}259} catch (IOException ee) {260env.error(where, "io.exception", "package check");261}262// This error message is also emitted for 'new' expressions.263// error(where, "class.not.found", e.name, "declaration");264error(where, "class.not.found.no.context", e.name);265return false;266}267return true;268}269270case TC_ARRAY:271return resolve(where, c, t.getElementType());272273case TC_METHOD:274boolean ok = resolve(where, c, t.getReturnType());275Type args[] = t.getArgumentTypes();276for (int i = args.length ; i-- > 0 ; ) {277ok &= resolve(where, c, args[i]);278}279return ok;280}281return true;282}283284/**285* Given its fully-qualified name, verify that a class is defined and accessible.286* Used to check components of qualified names in contexts where a class is expected.287* Like 'resolve', but is given a single type name, not a type descriptor.288*/289public boolean resolveByName(long where, ClassDefinition c, Identifier nm) {290return resolveByName(where, c, nm, false);291}292293public boolean resolveExtendsByName(long where, ClassDefinition c, Identifier nm) {294return resolveByName(where, c, nm, true);295}296297private boolean resolveByName(long where, ClassDefinition c,298Identifier nm, boolean isExtends) {299ClassDefinition def;300try {301if (!nm.isQualified() && !nm.isInner() && !classExists(nm)) {302resolve(nm); // elicit complaints about ambiguity303}304def = getQualifiedClassDefinition(where, nm, c, isExtends);305ClassDeclaration decl = def.getClassDeclaration();306if (!((!isExtends && c.canAccess(this, decl))307||308(isExtends && c.extendsCanAccess(this, decl)))) {309error(where, "cant.access.class", def);310return true; // return false later311}312} catch (AmbiguousClass ee) {313error(where, "ambig.class", ee.name1, ee.name2);314return false;315} catch (ClassNotFound e) {316// For now, report "class.and.package" only when the code317// is going to fail anyway.318try {319if (e.name.isInner() &&320getPackage(e.name.getTopName()).exists()) {321env.error(where, "class.and.package",322e.name.getTopName());323}324} catch (IOException ee) {325env.error(where, "io.exception", "package check");326}327error(where, "class.not.found", e.name, "type name");328return false;329}330return true;331}332333/**334* Like 'getClassDefinition(env)', but check access on each component.335* Currently called only by 'resolve' above. It is doubtful that calls336* to 'getClassDefinition(env)' are appropriate now.337*/338public final ClassDefinition339getQualifiedClassDefinition(long where,340Identifier nm,341ClassDefinition ctxClass,342boolean isExtends) throws ClassNotFound {343if (nm.isInner()) {344ClassDefinition c = getClassDefinition(nm.getTopName());345Identifier tail = nm.getFlatName();346walkTail:347while (tail.isQualified()) {348tail = tail.getTail();349Identifier head = tail.getHead();350// System.out.println("CLASS: " + c + " HEAD: " + head + " TAIL: " + tail);351String hname = head.toString();352// Handle synthesized names of local and anonymous classes.353// See 'getClassDefinition(env)' above.354if (hname.length() > 0355&& Character.isDigit(hname.charAt(0))) {356ClassDefinition localClass = c.getLocalClass(hname);357if (localClass != null) {358c = localClass;359continue walkTail;360}361} else {362for (MemberDefinition f = c.getFirstMatch(head);363f != null; f = f.getNextMatch()) {364if (f.isInnerClass()) {365ClassDeclaration rdecl = c.getClassDeclaration();366c = f.getInnerClass();367ClassDeclaration fdecl = c.getClassDeclaration();368// This check is presumably applicable even if the369// original source-code name (expanded by 'resolveNames')370// was a simple, unqualified name. Hopefully, JLS 2e371// will clarify the matter.372if ((!isExtends373&& !ctxClass.canAccess(env, fdecl))374||375(isExtends376&& !ctxClass.extendsCanAccess(env, fdecl))) {377// Reported error location is imprecise.378env.error(where, "no.type.access", head, rdecl, ctxClass);379}380// The JLS 6.6.2 restrictions on access to protected members381// depend in an essential way upon the syntactic form of the name.382// Since the compiler has previously expanded the class names383// here into fully-qualified form ('resolveNames'), this check384// cannot be performed here. Unfortunately, the original names385// are clobbered during 'basicCheck', which is also the phase that386// resolves the inheritance structure, required to implement the387// access restrictions. Pending a large-scale revision of the388// name-resolution machinery, we forgo this check, with the result389// that the JLS 6.6.2 restrictions are not enforced for some cases390// of qualified access to inner classes. Some qualified names are391// resolved elsewhere via a different mechanism, and will be392// treated correctly -- see 'FieldExpression.checkCommon'.393/*---------------------------------------*394if (f.isProtected()) {395Type rty = Type.tClass(rdecl.getName()); // hack396if (!ctxClass.protectedAccess(env, f, rty)) {397// Reported error location is imprecise.398env.error(where, "invalid.protected.type.use",399head, ctxClass, rty);400}401}402*---------------------------------------*/403continue walkTail;404}405}406}407throw new ClassNotFound(Identifier.lookupInner(c.getName(), head));408}409//System.out.println("FOUND " + c + " FOR " + nm);410return c;411}412return getClassDeclaration(nm).getClassDefinition(this);413}414415/**416* Resolve the names within a type, returning the adjusted type.417* Adjust class names to reflect scoping.418* Do not report errors.419* <p>420* NOTE: It would be convenient to check for errors here, such as421* verifying that each component of a qualified name exists and is422* accessible. Why must this be done in a separate phase?423* <p>424* If the 'synth' argument is true, indicating that the member whose425* type is being resolved is synthetic, names are resolved with respect426* to the package scope. (Fix for 4097882)427*/428public Type resolveNames(ClassDefinition c, Type t, boolean synth) {429if (tracing) dtEvent("Environment.resolveNames: " + c + ", " + t);430switch (t.getTypeCode()) {431case TC_CLASS: {432Identifier name = t.getClassName();433Identifier rname;434if (synth) {435rname = resolvePackageQualifiedName(name);436} else {437rname = c.resolveName(this, name);438}439if (name != rname) {440t = Type.tClass(rname);441}442break;443}444445case TC_ARRAY:446t = Type.tArray(resolveNames(c, t.getElementType(), synth));447break;448449case TC_METHOD: {450Type ret = t.getReturnType();451Type rret = resolveNames(c, ret, synth);452Type args[] = t.getArgumentTypes();453Type rargs[] = new Type[args.length];454boolean changed = (ret != rret);455for (int i = args.length ; i-- > 0 ; ) {456Type arg = args[i];457Type rarg = resolveNames(c, arg, synth);458rargs[i] = rarg;459if (arg != rarg) {460changed = true;461}462}463if (changed) {464t = Type.tMethod(rret, rargs);465}466break;467}468}469return t;470}471472/**473* Resolve a class name, using only package and import directives.474* Report no errors.475* <p>476*/477public Identifier resolveName(Identifier name) {478// This logic is pretty exactly parallel to that of479// ClassDefinition.resolveName().480if (name.isQualified()) {481// Try to resolve the first identifier component,482// because inner class names take precedence over483// package prefixes. (Cf. ClassDefinition.resolveName.)484Identifier rhead = resolveName(name.getHead());485486if (rhead.hasAmbigPrefix()) {487// The first identifier component refers to an488// ambiguous class. Limp on. We throw away the489// rest of the classname as it is irrelevant.490// (part of solution for 4059855).491return rhead;492}493494if (!this.classExists(rhead)) {495return this.resolvePackageQualifiedName(name);496}497try {498return this.getClassDefinition(rhead).499resolveInnerClass(this, name.getTail());500} catch (ClassNotFound ee) {501// return partially-resolved name someone else can fail on502return Identifier.lookupInner(rhead, name.getTail());503}504}505try {506return resolve(name);507} catch (AmbiguousClass ee) {508// Don't force a resolution of the name if it is ambiguous.509// Forcing the resolution would tack the current package510// name onto the front of the class, which would be wrong.511// Instead, mark the name as ambiguous and let a later stage512// find the error by calling env.resolve(name).513// (part of solution for 4059855).514515if (name.hasAmbigPrefix()) {516return name;517} else {518return name.addAmbigPrefix();519}520} catch (ClassNotFound ee) {521// last chance to make something halfway sensible522Imports imports = getImports();523if (imports != null)524return imports.forceResolve(this, name);525}526return name;527}528529/**530* Discover if name consists of a package prefix, followed by the531* name of a class (that actually exists), followed possibly by532* some inner class names. If we can't find a class that exists,533* return the name unchanged.534* <p>535* This routine is used after a class name fails to536* be resolved by means of imports or inner classes.537* However, import processing uses this routine directly,538* since import names must be exactly qualified to start with.539*/540public final Identifier resolvePackageQualifiedName(Identifier name) {541Identifier tail = null;542for (;;) {543if (classExists(name)) {544break;545}546if (!name.isQualified()) {547name = (tail == null) ? name : Identifier.lookup(name, tail);548tail = null;549break;550}551Identifier nm = name.getName();552tail = (tail == null)? nm: Identifier.lookup(nm, tail);553name = name.getQualifier();554}555if (tail != null)556name = Identifier.lookupInner(name, tail);557return name;558}559560/**561* Resolve a class name, using only package and import directives.562*/563public Identifier resolve(Identifier nm) throws ClassNotFound {564if (env == null) return nm; // a pretty useless no-op565return env.resolve(nm);566}567568/**569* Get the imports used to resolve class names.570*/571public Imports getImports() {572if (env == null) return null; // lame default573return env.getImports();574}575576/**577* Create a new class.578*/579public ClassDefinition makeClassDefinition(Environment origEnv, long where,580IdentifierToken name,581String doc, int modifiers,582IdentifierToken superClass,583IdentifierToken interfaces[],584ClassDefinition outerClass) {585if (env == null) return null; // lame default586return env.makeClassDefinition(origEnv, where, name,587doc, modifiers,588superClass, interfaces, outerClass);589}590591/**592* Create a new field.593*/594public MemberDefinition makeMemberDefinition(Environment origEnv, long where,595ClassDefinition clazz,596String doc, int modifiers,597Type type, Identifier name,598IdentifierToken argNames[],599IdentifierToken expIds[],600Object value) {601if (env == null) return null; // lame default602return env.makeMemberDefinition(origEnv, where, clazz, doc, modifiers,603type, name, argNames, expIds, value);604}605606/**607* Returns true if the given method is applicable to the given arguments608*/609610public boolean isApplicable(MemberDefinition m, Type args[]) throws ClassNotFound {611Type mType = m.getType();612if (!mType.isType(TC_METHOD))613return false;614Type mArgs[] = mType.getArgumentTypes();615if (args.length != mArgs.length)616return false;617for (int i = args.length ; --i >= 0 ;)618if (!isMoreSpecific(args[i], mArgs[i]))619return false;620return true;621}622623624/**625* Returns true if "best" is in every argument at least as good as "other"626*/627public boolean isMoreSpecific(MemberDefinition best, MemberDefinition other)628throws ClassNotFound {629Type bestType = best.getClassDeclaration().getType();630Type otherType = other.getClassDeclaration().getType();631boolean result = isMoreSpecific(bestType, otherType)632&& isApplicable(other, best.getType().getArgumentTypes());633// System.out.println("isMoreSpecific: " + best + "/" + other634// + " => " + result);635return result;636}637638/**639* Returns true if "from" is a more specific type than "to"640*/641642public boolean isMoreSpecific(Type from, Type to) throws ClassNotFound {643return implicitCast(from, to);644}645646/**647* Return true if an implicit cast from this type to648* the given type is allowed.649*/650public boolean implicitCast(Type from, Type to) throws ClassNotFound {651if (from == to)652return true;653654int toTypeCode = to.getTypeCode();655656switch(from.getTypeCode()) {657case TC_BYTE:658if (toTypeCode == TC_SHORT)659return true;660case TC_SHORT:661case TC_CHAR:662if (toTypeCode == TC_INT) return true;663case TC_INT:664if (toTypeCode == TC_LONG) return true;665case TC_LONG:666if (toTypeCode == TC_FLOAT) return true;667case TC_FLOAT:668if (toTypeCode == TC_DOUBLE) return true;669case TC_DOUBLE:670default:671return false;672673case TC_NULL:674return to.inMask(TM_REFERENCE);675676case TC_ARRAY:677if (!to.isType(TC_ARRAY)) {678return (to == Type.tObject || to == Type.tCloneable679|| to == Type.tSerializable);680} else {681// both are arrays. recurse down both until one isn't an array682do {683from = from.getElementType();684to = to.getElementType();685} while (from.isType(TC_ARRAY) && to.isType(TC_ARRAY));686if ( from.inMask(TM_ARRAY|TM_CLASS)687&& to.inMask(TM_ARRAY|TM_CLASS)) {688return isMoreSpecific(from, to);689} else {690return (from.getTypeCode() == to.getTypeCode());691}692}693694case TC_CLASS:695if (toTypeCode == TC_CLASS) {696ClassDefinition fromDef = getClassDefinition(from);697ClassDefinition toDef = getClassDefinition(to);698return toDef.implementedBy(this,699fromDef.getClassDeclaration());700} else {701return false;702}703}704}705706707/**708* Return true if an explicit cast from this type to709* the given type is allowed.710*/711public boolean explicitCast(Type from, Type to) throws ClassNotFound {712if (implicitCast(from, to)) {713return true;714}715if (from.inMask(TM_NUMBER)) {716return to.inMask(TM_NUMBER);717}718if (from.isType(TC_CLASS) && to.isType(TC_CLASS)) {719ClassDefinition fromClass = getClassDefinition(from);720ClassDefinition toClass = getClassDefinition(to);721if (toClass.isFinal()) {722return fromClass.implementedBy(this,723toClass.getClassDeclaration());724}725if (fromClass.isFinal()) {726return toClass.implementedBy(this,727fromClass.getClassDeclaration());728}729730// The code here used to omit this case. If both types731// involved in a cast are interfaces, then JLS 5.5 requires732// that we do a simple test -- make sure none of the methods733// in toClass and fromClass have the same signature but734// different return types. (bug number 4028359)735if (toClass.isInterface() && fromClass.isInterface()) {736return toClass.couldImplement(fromClass);737}738739return toClass.isInterface() ||740fromClass.isInterface() ||741fromClass.superClassOf(this, toClass.getClassDeclaration());742}743if (to.isType(TC_ARRAY)) {744if (from.isType(TC_ARRAY)) {745Type t1 = from.getElementType();746Type t2 = to.getElementType();747while ((t1.getTypeCode() == TC_ARRAY)748&& (t2.getTypeCode() == TC_ARRAY)) {749t1 = t1.getElementType();750t2 = t2.getElementType();751}752if (t1.inMask(TM_ARRAY|TM_CLASS) &&753t2.inMask(TM_ARRAY|TM_CLASS)) {754return explicitCast(t1, t2);755}756} else if (from == Type.tObject || from == Type.tCloneable757|| from == Type.tSerializable)758return true;759}760return false;761}762763/**764* Flags.765*/766public int getFlags() {767return env.getFlags();768}769770/**771* Debugging flags. There used to be a method debug()772* that has been replaced because -g has changed meaning773* (it now cooperates with -O and line number, variable774* range and source file info can be toggled separately).775*/776public final boolean debug_lines() {777return (getFlags() & F_DEBUG_LINES) != 0;778}779public final boolean debug_vars() {780return (getFlags() & F_DEBUG_VARS) != 0;781}782public final boolean debug_source() {783return (getFlags() & F_DEBUG_SOURCE) != 0;784}785786/**787* Optimization flags. There used to be a method optimize()788* that has been replaced because -O has changed meaning in789* javac to be replaced with -O and -O:interclass.790*/791public final boolean opt() {792return (getFlags() & F_OPT) != 0;793}794public final boolean opt_interclass() {795return (getFlags() & F_OPT_INTERCLASS) != 0;796}797798/**799* Verbose800*/801public final boolean verbose() {802return (getFlags() & F_VERBOSE) != 0;803}804805/**806* Dump debugging stuff807*/808public final boolean dump() {809return (getFlags() & F_DUMP) != 0;810}811812/**813* Verbose814*/815public final boolean warnings() {816return (getFlags() & F_WARNINGS) != 0;817}818819/**820* Dependencies821*/822public final boolean dependencies() {823return (getFlags() & F_DEPENDENCIES) != 0;824}825826/**827* Print Dependencies to stdout828*/829public final boolean print_dependencies() {830return (getFlags() & F_PRINT_DEPENDENCIES) != 0;831}832833/**834* Deprecation warnings are enabled.835*/836public final boolean deprecation() {837return (getFlags() & F_DEPRECATION) != 0;838}839840/**841* Do not support virtual machines before version 1.2.842* This option is not supported and is only here for testing purposes.843*/844public final boolean version12() {845return (getFlags() & F_VERSION12) != 0;846}847848/**849* Floating point is strict by default850*/851public final boolean strictdefault() {852return (getFlags() & F_STRICTDEFAULT) != 0;853}854855/**856* Release resources, if any.857*/858public void shutdown() {859if (env != null) {860env.shutdown();861}862}863864/**865* Issue an error.866* source - the input source, usually a file name string867* offset - the offset in the source of the error868* err - the error number (as defined in this interface)869* arg1 - an optional argument to the error (null if not applicable)870* arg2 - a second optional argument to the error (null if not applicable)871* arg3 - a third optional argument to the error (null if not applicable)872*/873public void error(Object source, long where, String err, Object arg1, Object arg2, Object arg3) {874env.error(source, where, err, arg1, arg2, arg3);875}876public final void error(long where, String err, Object arg1, Object arg2, Object arg3) {877error(source, where, err, arg1, arg2, arg3);878}879public final void error(long where, String err, Object arg1, Object arg2) {880error(source, where, err, arg1, arg2, null);881}882public final void error(long where, String err, Object arg1) {883error(source, where, err, arg1, null, null);884}885public final void error(long where, String err) {886error(source, where, err, null, null, null);887}888889/**890* Output a string. This can either be an error message or something891* for debugging. This should be used instead of println.892*/893public void output(String msg) {894env.output(msg);895}896897private static boolean debugging = (System.getProperty("javac.debug") != null);898899public static void debugOutput(Object msg) {900if (Environment.debugging)901System.out.println(msg.toString());902}903904/**905* set character encoding name906*/907public void setCharacterEncoding(String encoding) {908this.encoding = encoding;909}910911/**912* Return character encoding name913*/914public String getCharacterEncoding() {915return encoding;916}917918/**919* Return major version to use in generated class files.920*/921public short getMajorVersion() {922if (env==null) return JAVA_DEFAULT_VERSION; // needed for javah923return env.getMajorVersion();924}925926/**927* Return minor version to use in generated class files.928*/929public short getMinorVersion() {930if (env==null) return JAVA_DEFAULT_MINOR_VERSION; // needed for javah931return env.getMinorVersion();932}933934// JCOV935/**936* get coverage flag937*/938public final boolean coverage() {939return (getFlags() & F_COVERAGE) != 0;940}941942/**943* get flag of generation the coverage data file944*/945public final boolean covdata() {946return (getFlags() & F_COVDATA) != 0;947}948949/**950* Return the coverage data file951*/952public File getcovFile() {953return env.getcovFile();954}955956// end JCOV957958/**959* Debug tracing.960* Currently, this code is used only for tracing the loading and961* checking of classes, particularly the demand-driven aspects.962* This code should probably be integrated with 'debugOutput' above,963* but we need to give more thought to the issue of classifying debugging964* messages and allowing those only those of interest to be enabled.965*966* Calls to these methods are generally conditioned on the final variable967* 'Constants.tracing', which allows the calls to be completely omitted968* in a production release to avoid space and time overhead.969*/970971private static boolean dependtrace =972(System.getProperty("javac.trace.depend") != null);973974public void dtEnter(String s) {975if (dependtrace) System.out.println(">>> " + s);976}977978public void dtExit(String s) {979if (dependtrace) System.out.println("<<< " + s);980}981982public void dtEvent(String s) {983if (dependtrace) System.out.println(s);984}985986/**987* Enable diagnostic dump of class modifier bits, including those988* in InnerClasses attributes, as they are written to the classfile.989* In the future, may also enable dumping field and method modifiers.990*/991992private static boolean dumpmodifiers =993(System.getProperty("javac.dump.modifiers") != null);994995public boolean dumpModifiers() { return dumpmodifiers; }996997}9989991000