author | ntoda |
Thu, 31 Jul 2014 17:01:24 -0700 | |
changeset 25799 | 1afc4675dc75 |
parent 25522 | 10d789df41bb |
permissions | -rw-r--r-- |
2 | 1 |
/* |
5506 | 2 |
* Copyright (c) 1994, 2003, Oracle and/or its affiliates. All rights reserved. |
2 | 3 |
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
4 |
* |
|
5 |
* This code is free software; you can redistribute it and/or modify it |
|
6 |
* under the terms of the GNU General Public License version 2 only, as |
|
5506 | 7 |
* published by the Free Software Foundation. Oracle designates this |
2 | 8 |
* particular file as subject to the "Classpath" exception as provided |
5506 | 9 |
* by Oracle in the LICENSE file that accompanied this code. |
2 | 10 |
* |
11 |
* This code is distributed in the hope that it will be useful, but WITHOUT |
|
12 |
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
|
13 |
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
|
14 |
* version 2 for more details (a copy is included in the LICENSE file that |
|
15 |
* accompanied this code). |
|
16 |
* |
|
17 |
* You should have received a copy of the GNU General Public License version |
|
18 |
* 2 along with this work; if not, write to the Free Software Foundation, |
|
19 |
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
|
20 |
* |
|
5506 | 21 |
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
22 |
* or visit www.oracle.com if you need additional information or have any |
|
23 |
* questions. |
|
2 | 24 |
*/ |
25 |
||
26 |
package sun.tools.java; |
|
27 |
||
28 |
import java.util.Hashtable; |
|
29 |
import java.io.PrintStream; |
|
30 |
import java.util.Enumeration; |
|
31 |
||
32 |
/** |
|
33 |
* A class to represent identifiers.<p> |
|
34 |
* |
|
35 |
* An identifier instance is very similar to a String. The difference |
|
36 |
* is that identifier can't be instanciated directly, instead they are |
|
37 |
* looked up in a hash table. This means that identifiers with the same |
|
38 |
* name map to the same identifier object. This makes comparisons of |
|
39 |
* identifiers much faster.<p> |
|
40 |
* |
|
41 |
* A lot of identifiers are qualified, that is they have '.'s in them. |
|
42 |
* Each qualified identifier is chopped up into the qualifier and the |
|
43 |
* name. The qualifier is cached in the value field.<p> |
|
44 |
* |
|
45 |
* Unqualified identifiers can have a type. This type is an integer that |
|
46 |
* can be used by a scanner as a token value. This value has to be set |
|
47 |
* using the setType method.<p> |
|
48 |
* |
|
49 |
* WARNING: The contents of this source file are not part of any |
|
50 |
* supported API. Code that depends on them does so at its own risk: |
|
51 |
* they are subject to change or removal without notice. |
|
52 |
* |
|
53 |
* @author Arthur van Hoff |
|
54 |
*/ |
|
55 |
||
56 |
public final |
|
57 |
class Identifier implements Constants { |
|
58 |
/** |
|
59 |
* The hashtable of identifiers |
|
60 |
*/ |
|
25799
1afc4675dc75
8044867: Fix raw and unchecked lint warnings in sun.tools.*
ntoda
parents:
25522
diff
changeset
|
61 |
static Hashtable<String, Identifier> hash = new Hashtable<>(3001, 0.5f); |
2 | 62 |
|
63 |
/** |
|
64 |
* The name of the identifier |
|
65 |
*/ |
|
66 |
String name; |
|
67 |
||
68 |
/** |
|
69 |
* The value of the identifier, for keywords this is an |
|
70 |
* instance of class Integer, for qualified names this is |
|
71 |
* another identifier (the qualifier). |
|
72 |
*/ |
|
73 |
Object value; |
|
74 |
||
75 |
/** |
|
76 |
* The Type which corresponds to this Identifier. This is used as |
|
77 |
* cache for Type.tClass() and shouldn't be used outside of that |
|
78 |
* context. |
|
79 |
*/ |
|
80 |
Type typeObject = null; |
|
81 |
||
82 |
/** |
|
83 |
* The index of INNERCLASS_PREFIX in the name, or -1 if none. |
|
84 |
*/ |
|
85 |
private int ipos; |
|
86 |
||
87 |
/** |
|
88 |
* Construct an identifier. Don't call this directly, |
|
89 |
* use lookup instead. |
|
90 |
* @see Identifier.lookup |
|
91 |
*/ |
|
92 |
private Identifier(String name) { |
|
93 |
this.name = name; |
|
94 |
this.ipos = name.indexOf(INNERCLASS_PREFIX); |
|
95 |
} |
|
96 |
||
97 |
/** |
|
98 |
* Get the type of the identifier. |
|
99 |
*/ |
|
100 |
int getType() { |
|
101 |
return ((value != null) && (value instanceof Integer)) ? |
|
102 |
((Integer)value).intValue() : IDENT; |
|
103 |
} |
|
104 |
||
105 |
/** |
|
106 |
* Set the type of the identifier. |
|
107 |
*/ |
|
108 |
void setType(int t) { |
|
25522
10d789df41bb
8049892: Replace uses of 'new Integer()' with appropriate alternative across core classes
prr
parents:
5506
diff
changeset
|
109 |
value = t; |
2 | 110 |
//System.out.println("type(" + this + ")=" + t); |
111 |
} |
|
112 |
||
113 |
/** |
|
114 |
* Lookup an identifier. |
|
115 |
*/ |
|
116 |
public static synchronized Identifier lookup(String s) { |
|
117 |
//System.out.println("lookup(" + s + ")"); |
|
25799
1afc4675dc75
8044867: Fix raw and unchecked lint warnings in sun.tools.*
ntoda
parents:
25522
diff
changeset
|
118 |
Identifier id = hash.get(s); |
2 | 119 |
if (id == null) { |
120 |
hash.put(s, id = new Identifier(s)); |
|
121 |
} |
|
122 |
return id; |
|
123 |
} |
|
124 |
||
125 |
/** |
|
126 |
* Lookup a qualified identifier. |
|
127 |
*/ |
|
128 |
public static Identifier lookup(Identifier q, Identifier n) { |
|
129 |
// lookup("", x) => x |
|
130 |
if (q == idNull) return n; |
|
131 |
// lookup(lookupInner(c, ""), n) => lookupInner(c, lookup("", n)) |
|
132 |
if (q.name.charAt(q.name.length()-1) == INNERCLASS_PREFIX) |
|
133 |
return lookup(q.name+n.name); |
|
134 |
Identifier id = lookup(q + "." + n); |
|
135 |
if (!n.isQualified() && !q.isInner()) |
|
136 |
id.value = q; |
|
137 |
return id; |
|
138 |
} |
|
139 |
||
140 |
/** |
|
141 |
* Lookup an inner identifier. |
|
142 |
* (Note: n can be idNull.) |
|
143 |
*/ |
|
144 |
public static Identifier lookupInner(Identifier c, Identifier n) { |
|
145 |
Identifier id; |
|
146 |
if (c.isInner()) { |
|
147 |
if (c.name.charAt(c.name.length()-1) == INNERCLASS_PREFIX) |
|
148 |
id = lookup(c.name+n); |
|
149 |
else |
|
150 |
id = lookup(c, n); |
|
151 |
} else { |
|
152 |
id = lookup(c + "." + INNERCLASS_PREFIX + n); |
|
153 |
} |
|
154 |
id.value = c.value; |
|
155 |
return id; |
|
156 |
} |
|
157 |
||
158 |
/** |
|
159 |
* Convert to a string. |
|
160 |
*/ |
|
161 |
public String toString() { |
|
162 |
return name; |
|
163 |
} |
|
164 |
||
165 |
/** |
|
166 |
* Check if the name is qualified (ie: it contains a '.'). |
|
167 |
*/ |
|
168 |
public boolean isQualified() { |
|
169 |
if (value == null) { |
|
170 |
int idot = ipos; |
|
171 |
if (idot <= 0) |
|
172 |
idot = name.length(); |
|
173 |
else |
|
174 |
idot -= 1; // back up over previous dot |
|
175 |
int index = name.lastIndexOf('.', idot-1); |
|
176 |
value = (index < 0) ? idNull : Identifier.lookup(name.substring(0, index)); |
|
177 |
} |
|
178 |
return (value instanceof Identifier) && (value != idNull); |
|
179 |
} |
|
180 |
||
181 |
/** |
|
182 |
* Return the qualifier. The null identifier is returned if |
|
183 |
* the name was not qualified. The qualifier does not include |
|
184 |
* any inner part of the name. |
|
185 |
*/ |
|
186 |
public Identifier getQualifier() { |
|
187 |
return isQualified() ? (Identifier)value : idNull; |
|
188 |
} |
|
189 |
||
190 |
/** |
|
191 |
* Return the unqualified name. |
|
192 |
* In the case of an inner name, the unqualified name |
|
193 |
* will itself contain components. |
|
194 |
*/ |
|
195 |
public Identifier getName() { |
|
196 |
return isQualified() ? |
|
197 |
Identifier.lookup(name.substring(((Identifier)value).name.length() + 1)) : this; |
|
198 |
} |
|
199 |
||
200 |
/** A space character, which precedes the first inner class |
|
201 |
* name in a qualified name, and thus marks the qualification |
|
202 |
* as involving inner classes, instead of merely packages.<p> |
|
203 |
* Ex: <tt>java.util.Vector. Enumerator</tt>. |
|
204 |
*/ |
|
205 |
public static final char INNERCLASS_PREFIX = ' '; |
|
206 |
||
207 |
/* Explanation: |
|
208 |
* Since much of the compiler's low-level name resolution code |
|
209 |
* operates in terms of Identifier objects. This includes the |
|
210 |
* code which walks around the file system and reports what |
|
211 |
* classes are where. It is important to get nesting information |
|
212 |
* right as early as possible, since it affects the spelling of |
|
213 |
* signatures. Thus, the low-level import and resolve code must |
|
214 |
* be able Identifier type must be able to report the nesting |
|
215 |
* of types, which implied that that information must be carried |
|
216 |
* by Identifiers--or that the low-level interfaces be significantly |
|
217 |
* changed. |
|
218 |
*/ |
|
219 |
||
220 |
/** |
|
221 |
* Check if the name is inner (ie: it contains a ' '). |
|
222 |
*/ |
|
223 |
public boolean isInner() { |
|
224 |
return (ipos > 0); |
|
225 |
} |
|
226 |
||
227 |
/** |
|
228 |
* Return the class name, without its qualifier, |
|
229 |
* and with any nesting flattened into a new qualfication structure. |
|
230 |
* If the original identifier is inner, |
|
231 |
* the result will be qualified, and can be further |
|
232 |
* decomposed by means of <tt>getQualifier</tt> and <tt>getName</tt>. |
|
233 |
* <p> |
|
234 |
* For example: |
|
235 |
* <pre> |
|
236 |
* Identifier id = Identifier.lookup("pkg.Foo. Bar"); |
|
237 |
* id.getName().name => "Foo. Bar" |
|
238 |
* id.getFlatName().name => "Foo.Bar" |
|
239 |
* </pre> |
|
240 |
*/ |
|
241 |
public Identifier getFlatName() { |
|
242 |
if (isQualified()) { |
|
243 |
return getName().getFlatName(); |
|
244 |
} |
|
245 |
if (ipos > 0 && name.charAt(ipos-1) == '.') { |
|
246 |
if (ipos+1 == name.length()) { |
|
247 |
// last component is idNull |
|
248 |
return Identifier.lookup(name.substring(0,ipos-1)); |
|
249 |
} |
|
250 |
String n = name.substring(ipos+1); |
|
251 |
String t = name.substring(0,ipos); |
|
252 |
return Identifier.lookup(t+n); |
|
253 |
} |
|
254 |
// Not inner. Just return the same as getName() |
|
255 |
return this; |
|
256 |
} |
|
257 |
||
258 |
public Identifier getTopName() { |
|
259 |
if (!isInner()) return this; |
|
260 |
return Identifier.lookup(getQualifier(), getFlatName().getHead()); |
|
261 |
} |
|
262 |
||
263 |
/** |
|
264 |
* Yet another way to slice qualified identifiers: |
|
265 |
* The head of an identifier is its first qualifier component, |
|
266 |
* and the tail is the rest of them. |
|
267 |
*/ |
|
268 |
public Identifier getHead() { |
|
269 |
Identifier id = this; |
|
270 |
while (id.isQualified()) |
|
271 |
id = id.getQualifier(); |
|
272 |
return id; |
|
273 |
} |
|
274 |
||
275 |
/** |
|
276 |
* @see getHead |
|
277 |
*/ |
|
278 |
public Identifier getTail() { |
|
279 |
Identifier id = getHead(); |
|
280 |
if (id == this) |
|
281 |
return idNull; |
|
282 |
else |
|
283 |
return Identifier.lookup(name.substring(id.name.length() + 1)); |
|
284 |
} |
|
285 |
||
286 |
// Unfortunately, the current structure of the compiler requires |
|
287 |
// that the resolveName() family of methods (which appear in |
|
288 |
// Environment.java, Context.java, and ClassDefinition.java) raise |
|
289 |
// no exceptions and emit no errors. When we are in resolveName() |
|
290 |
// and we find a method that is ambiguous, we need to |
|
291 |
// unambiguously mark it as such, so that later stages of the |
|
292 |
// compiler realize that they should give an ambig.class rather than |
|
293 |
// a class.not.found error. To mark it we add a special prefix |
|
294 |
// which cannot occur in the program source. The routines below |
|
295 |
// are used to check, add, and remove this prefix. |
|
296 |
// (part of solution for 4059855). |
|
297 |
||
298 |
/** |
|
299 |
* A special prefix to add to ambiguous names. |
|
300 |
*/ |
|
301 |
private static final String ambigPrefix = "<<ambiguous>>"; |
|
302 |
||
303 |
/** |
|
304 |
* Determine whether an Identifier has been marked as ambiguous. |
|
305 |
*/ |
|
306 |
public boolean hasAmbigPrefix() { |
|
307 |
return (name.startsWith(ambigPrefix)); |
|
308 |
} |
|
309 |
||
310 |
/** |
|
311 |
* Add ambigPrefix to `this' to make a new Identifier marked as |
|
312 |
* ambiguous. It is important that this new Identifier not refer |
|
313 |
* to an existing class. |
|
314 |
*/ |
|
315 |
public Identifier addAmbigPrefix() { |
|
316 |
return Identifier.lookup(ambigPrefix + name); |
|
317 |
} |
|
318 |
||
319 |
/** |
|
320 |
* Remove the ambigPrefix from `this' to get the original identifier. |
|
321 |
*/ |
|
322 |
public Identifier removeAmbigPrefix() { |
|
323 |
if (hasAmbigPrefix()) { |
|
324 |
return Identifier.lookup(name.substring(ambigPrefix.length())); |
|
325 |
} else { |
|
326 |
return this; |
|
327 |
} |
|
328 |
} |
|
329 |
} |