Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/sun/tools/java/Identifier.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.io.PrintStream;29import java.util.Enumeration;3031/**32* A class to represent identifiers.<p>33*34* An identifier instance is very similar to a String. The difference35* is that identifier can't be instanciated directly, instead they are36* looked up in a hash table. This means that identifiers with the same37* name map to the same identifier object. This makes comparisons of38* identifiers much faster.<p>39*40* A lot of identifiers are qualified, that is they have '.'s in them.41* Each qualified identifier is chopped up into the qualifier and the42* name. The qualifier is cached in the value field.<p>43*44* Unqualified identifiers can have a type. This type is an integer that45* can be used by a scanner as a token value. This value has to be set46* using the setType method.<p>47*48* WARNING: The contents of this source file are not part of any49* supported API. Code that depends on them does so at its own risk:50* they are subject to change or removal without notice.51*52* @author Arthur van Hoff53*/5455public final56class Identifier implements Constants {57/**58* The hashtable of identifiers59*/60static Hashtable hash = new Hashtable(3001, 0.5f);6162/**63* The name of the identifier64*/65String name;6667/**68* The value of the identifier, for keywords this is an69* instance of class Integer, for qualified names this is70* another identifier (the qualifier).71*/72Object value;7374/**75* The Type which corresponds to this Identifier. This is used as76* cache for Type.tClass() and shouldn't be used outside of that77* context.78*/79Type typeObject = null;8081/**82* The index of INNERCLASS_PREFIX in the name, or -1 if none.83*/84private int ipos;8586/**87* Construct an identifier. Don't call this directly,88* use lookup instead.89* @see Identifier.lookup90*/91private Identifier(String name) {92this.name = name;93this.ipos = name.indexOf(INNERCLASS_PREFIX);94}9596/**97* Get the type of the identifier.98*/99int getType() {100return ((value != null) && (value instanceof Integer)) ?101((Integer)value).intValue() : IDENT;102}103104/**105* Set the type of the identifier.106*/107void setType(int t) {108value = new Integer(t);109//System.out.println("type(" + this + ")=" + t);110}111112/**113* Lookup an identifier.114*/115public static synchronized Identifier lookup(String s) {116//System.out.println("lookup(" + s + ")");117Identifier id = (Identifier)hash.get(s);118if (id == null) {119hash.put(s, id = new Identifier(s));120}121return id;122}123124/**125* Lookup a qualified identifier.126*/127public static Identifier lookup(Identifier q, Identifier n) {128// lookup("", x) => x129if (q == idNull) return n;130// lookup(lookupInner(c, ""), n) => lookupInner(c, lookup("", n))131if (q.name.charAt(q.name.length()-1) == INNERCLASS_PREFIX)132return lookup(q.name+n.name);133Identifier id = lookup(q + "." + n);134if (!n.isQualified() && !q.isInner())135id.value = q;136return id;137}138139/**140* Lookup an inner identifier.141* (Note: n can be idNull.)142*/143public static Identifier lookupInner(Identifier c, Identifier n) {144Identifier id;145if (c.isInner()) {146if (c.name.charAt(c.name.length()-1) == INNERCLASS_PREFIX)147id = lookup(c.name+n);148else149id = lookup(c, n);150} else {151id = lookup(c + "." + INNERCLASS_PREFIX + n);152}153id.value = c.value;154return id;155}156157/**158* Convert to a string.159*/160public String toString() {161return name;162}163164/**165* Check if the name is qualified (ie: it contains a '.').166*/167public boolean isQualified() {168if (value == null) {169int idot = ipos;170if (idot <= 0)171idot = name.length();172else173idot -= 1; // back up over previous dot174int index = name.lastIndexOf('.', idot-1);175value = (index < 0) ? idNull : Identifier.lookup(name.substring(0, index));176}177return (value instanceof Identifier) && (value != idNull);178}179180/**181* Return the qualifier. The null identifier is returned if182* the name was not qualified. The qualifier does not include183* any inner part of the name.184*/185public Identifier getQualifier() {186return isQualified() ? (Identifier)value : idNull;187}188189/**190* Return the unqualified name.191* In the case of an inner name, the unqualified name192* will itself contain components.193*/194public Identifier getName() {195return isQualified() ?196Identifier.lookup(name.substring(((Identifier)value).name.length() + 1)) : this;197}198199/** A space character, which precedes the first inner class200* name in a qualified name, and thus marks the qualification201* as involving inner classes, instead of merely packages.<p>202* Ex: <tt>java.util.Vector. Enumerator</tt>.203*/204public static final char INNERCLASS_PREFIX = ' ';205206/* Explanation:207* Since much of the compiler's low-level name resolution code208* operates in terms of Identifier objects. This includes the209* code which walks around the file system and reports what210* classes are where. It is important to get nesting information211* right as early as possible, since it affects the spelling of212* signatures. Thus, the low-level import and resolve code must213* be able Identifier type must be able to report the nesting214* of types, which implied that that information must be carried215* by Identifiers--or that the low-level interfaces be significantly216* changed.217*/218219/**220* Check if the name is inner (ie: it contains a ' ').221*/222public boolean isInner() {223return (ipos > 0);224}225226/**227* Return the class name, without its qualifier,228* and with any nesting flattened into a new qualfication structure.229* If the original identifier is inner,230* the result will be qualified, and can be further231* decomposed by means of <tt>getQualifier</tt> and <tt>getName</tt>.232* <p>233* For example:234* <pre>235* Identifier id = Identifier.lookup("pkg.Foo. Bar");236* id.getName().name => "Foo. Bar"237* id.getFlatName().name => "Foo.Bar"238* </pre>239*/240public Identifier getFlatName() {241if (isQualified()) {242return getName().getFlatName();243}244if (ipos > 0 && name.charAt(ipos-1) == '.') {245if (ipos+1 == name.length()) {246// last component is idNull247return Identifier.lookup(name.substring(0,ipos-1));248}249String n = name.substring(ipos+1);250String t = name.substring(0,ipos);251return Identifier.lookup(t+n);252}253// Not inner. Just return the same as getName()254return this;255}256257public Identifier getTopName() {258if (!isInner()) return this;259return Identifier.lookup(getQualifier(), getFlatName().getHead());260}261262/**263* Yet another way to slice qualified identifiers:264* The head of an identifier is its first qualifier component,265* and the tail is the rest of them.266*/267public Identifier getHead() {268Identifier id = this;269while (id.isQualified())270id = id.getQualifier();271return id;272}273274/**275* @see getHead276*/277public Identifier getTail() {278Identifier id = getHead();279if (id == this)280return idNull;281else282return Identifier.lookup(name.substring(id.name.length() + 1));283}284285// Unfortunately, the current structure of the compiler requires286// that the resolveName() family of methods (which appear in287// Environment.java, Context.java, and ClassDefinition.java) raise288// no exceptions and emit no errors. When we are in resolveName()289// and we find a method that is ambiguous, we need to290// unambiguously mark it as such, so that later stages of the291// compiler realize that they should give an ambig.class rather than292// a class.not.found error. To mark it we add a special prefix293// which cannot occur in the program source. The routines below294// are used to check, add, and remove this prefix.295// (part of solution for 4059855).296297/**298* A special prefix to add to ambiguous names.299*/300private static final String ambigPrefix = "<<ambiguous>>";301302/**303* Determine whether an Identifier has been marked as ambiguous.304*/305public boolean hasAmbigPrefix() {306return (name.startsWith(ambigPrefix));307}308309/**310* Add ambigPrefix to `this' to make a new Identifier marked as311* ambiguous. It is important that this new Identifier not refer312* to an existing class.313*/314public Identifier addAmbigPrefix() {315return Identifier.lookup(ambigPrefix + name);316}317318/**319* Remove the ambigPrefix from `this' to get the original identifier.320*/321public Identifier removeAmbigPrefix() {322if (hasAmbigPrefix()) {323return Identifier.lookup(name.substring(ambigPrefix.length()));324} else {325return this;326}327}328}329330331