• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2008 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package org.apache.harmony.luni.lang.reflect;
18 
19 import java.lang.reflect.Constructor;
20 import java.lang.reflect.GenericDeclaration;
21 import java.lang.reflect.GenericSignatureFormatError;
22 import java.lang.reflect.Method;
23 import java.lang.reflect.Type;
24 import java.lang.reflect.TypeVariable;
25 
26 /**
27  * Implements a parser for the generics signature attribute.
28  * Uses a top-down, recursive descent parsing approach for the following grammar:
29  * <pre>
30  * ClassSignature ::=
31  *     OptFormalTypeParams SuperclassSignature {SuperinterfaceSignature}.
32  * SuperclassSignature ::= ClassTypeSignature.
33  * SuperinterfaceSignature ::= ClassTypeSignature.
34  *
35  * OptFormalTypeParams ::=
36  *     ["<" FormalTypeParameter {FormalTypeParameter} ">"].
37  *
38  * FormalTypeParameter ::= Ident ClassBound {InterfaceBound}.
39  * ClassBound ::= ":" [FieldTypeSignature].
40  * InterfaceBound ::= ":" FieldTypeSignature.
41  *
42  * FieldTypeSignature ::=
43  *     ClassTypeSignature | ArrayTypeSignature | TypeVariableSignature.
44  * ArrayTypeSignature ::= "[" TypSignature.
45  *
46  * ClassTypeSignature ::=
47  *     "L" {Ident "/"} Ident OptTypeArguments {"." Ident OptTypeArguments} ";".
48  *
49  * OptTypeArguments ::= "<" TypeArgument {TypeArgument} ">".
50  *
51  * TypeArgument ::= ([WildcardIndicator] FieldTypeSignature) | "*".
52  * WildcardIndicator ::= "+" | "-".
53  *
54  * TypeVariableSignature ::= "T" Ident ";".
55  *
56  * TypSignature ::= FieldTypeSignature | BaseType.
57  * BaseType ::= "B" | "C" | "D" | "F" | "I" | "J" | "S" | "Z".
58  *
59  * MethodTypeSignature ::=
60  *     OptFormalTypeParams "(" {TypeSignature} ")" ReturnType {ThrowsSignature}.
61  * ThrowsSignature ::= ("^" ClassTypeSignature) | ("^" TypeVariableSignature).
62  *
63  * ReturnType ::= TypSignature | VoidDescriptor.
64  * VoidDescriptor ::= "V".
65  * </pre>
66  */
67 public class GenericSignatureParser {
68 
69     public ListOfTypes exceptionTypes;
70     public ListOfTypes parameterTypes;
71     public TypeVariable[] formalTypeParameters;
72     public Type returnType;
73     public Type fieldType;
74     public ListOfTypes interfaceTypes;
75     public Type superclassType;
76     public ClassLoader loader;
77 
78     GenericDeclaration genericDecl;
79 
80     /*
81      * Parser:
82      */
83     char symbol; // 0: eof; else valid term symbol or first char of identifier.
84     String identifier;
85 
86 
87     /*
88      * Scanner:
89      * eof is private to the scan methods
90      * and it's set only when a scan is issued at the end of the buffer.
91      */
92     private boolean eof;
93 
94     char[] buffer;
95     int pos;
96 
GenericSignatureParser(ClassLoader loader)97     public GenericSignatureParser(ClassLoader loader) {
98         this.loader = loader;
99     }
100 
setInput(GenericDeclaration genericDecl, String input)101     void setInput(GenericDeclaration genericDecl, String input) {
102         if (input != null) {
103             this.genericDecl = genericDecl;
104             this.buffer = input.toCharArray();
105             this.eof = false;
106             scanSymbol();
107         }
108         else {
109             this.eof = true;
110         }
111     }
112 
113     /**
114      * Parses the generic signature of a class and creates the data structure
115      * representing the signature.
116      *
117      * @param genericDecl the GenericDeclaration calling this method
118      * @param signature the generic signature of the class
119      */
parseForClass(GenericDeclaration genericDecl, String signature)120     public void parseForClass(GenericDeclaration genericDecl,
121             String signature) {
122         setInput(genericDecl, signature);
123         if (!eof) {
124             parseClassSignature();
125         } else {
126             if(genericDecl instanceof Class) {
127                 Class c = (Class) genericDecl;
128                 this.formalTypeParameters = ListOfVariables.EMPTY;
129                 this.superclassType = c.getSuperclass();
130                 this.interfaceTypes = new ListOfTypes(c.getInterfaces());
131             } else {
132                 this.formalTypeParameters = ListOfVariables.EMPTY;
133                 this.superclassType = Object.class;
134                 this.interfaceTypes = ListOfTypes.EMPTY;
135             }
136         }
137     }
138 
139     /**
140      * Parses the generic signature of a method and creates the data structure
141      * representing the signature.
142      *
143      * @param genericDecl the GenericDeclaration calling this method
144      * @param signature the generic signature of the class
145      */
parseForMethod(GenericDeclaration genericDecl, String signature, Class<?>[] rawExceptionTypes)146     public void parseForMethod(GenericDeclaration genericDecl,
147             String signature, Class<?>[] rawExceptionTypes) {
148         setInput(genericDecl, signature);
149         if (!eof) {
150             parseMethodTypeSignature(rawExceptionTypes);
151         } else {
152             if(genericDecl instanceof Method) {
153                 Method m = (Method) genericDecl;
154                 this.formalTypeParameters = ListOfVariables.EMPTY;
155                 this.parameterTypes = new ListOfTypes(m.getParameterTypes());
156                 this.exceptionTypes = new ListOfTypes(m.getExceptionTypes());
157                 this.returnType = m.getReturnType();
158             } else {
159                 this.formalTypeParameters = ListOfVariables.EMPTY;
160                 this.parameterTypes = ListOfTypes.EMPTY;
161                 this.exceptionTypes = ListOfTypes.EMPTY;
162                 this.returnType = void.class;
163             }
164         }
165     }
166 
167     /**
168      * Parses the generic signature of a constructor and creates the data
169      * structure representing the signature.
170      *
171      * @param genericDecl the GenericDeclaration calling this method
172      * @param signature the generic signature of the class
173      */
parseForConstructor(GenericDeclaration genericDecl, String signature, Class<?>[] rawExceptionTypes)174     public void parseForConstructor(GenericDeclaration genericDecl,
175             String signature, Class<?>[] rawExceptionTypes) {
176         setInput(genericDecl, signature);
177         if (!eof) {
178             parseMethodTypeSignature(rawExceptionTypes);
179         } else {
180             if(genericDecl instanceof Constructor) {
181                 Constructor c = (Constructor) genericDecl;
182                 this.formalTypeParameters = ListOfVariables.EMPTY;
183                 this.parameterTypes = new ListOfTypes(c.getParameterTypes());
184                 this.exceptionTypes = new ListOfTypes(c.getExceptionTypes());
185             } else {
186                 this.formalTypeParameters = ListOfVariables.EMPTY;
187                 this.parameterTypes = ListOfTypes.EMPTY;
188                 this.exceptionTypes = ListOfTypes.EMPTY;
189             }
190         }
191     }
192 
193     /**
194      * Parses the generic signature of a field and creates the data structure
195      * representing the signature.
196      *
197      * @param genericDecl the GenericDeclaration calling this method
198      * @param signature the generic signature of the class
199      */
parseForField(GenericDeclaration genericDecl, String signature)200     public void parseForField(GenericDeclaration genericDecl,
201             String signature) {
202         setInput(genericDecl, signature);
203         if (!eof) {
204             this.fieldType = parseFieldTypeSignature();
205         }
206     }
207 
208 
209     //
210     // Parser:
211     //
212 
parseClassSignature()213     void parseClassSignature() {
214         // ClassSignature ::=
215         // OptFormalTypeParameters SuperclassSignature {SuperinterfaceSignature}.
216 
217         parseOptFormalTypeParameters();
218 
219         // SuperclassSignature ::= ClassTypeSignature.
220         this.superclassType = parseClassTypeSignature();
221 
222         interfaceTypes = new ListOfTypes(16);
223         while (symbol > 0) {
224             // SuperinterfaceSignature ::= ClassTypeSignature.
225             interfaceTypes.add(parseClassTypeSignature());
226         }
227     }
228 
parseOptFormalTypeParameters()229     void parseOptFormalTypeParameters() {
230         // OptFormalTypeParameters ::=
231         // ["<" FormalTypeParameter {FormalTypeParameter} ">"].
232 
233         ListOfVariables typeParams = new ListOfVariables();
234 
235         if (symbol == '<') {
236             scanSymbol();
237             typeParams.add(parseFormalTypeParameter());
238             while ((symbol != '>') && (symbol > 0)) {
239                 typeParams.add(parseFormalTypeParameter());
240             }
241             expect('>');
242         }
243         this.formalTypeParameters = typeParams.getArray();
244     }
245 
parseFormalTypeParameter()246     ImplForVariable<GenericDeclaration> parseFormalTypeParameter() {
247         // FormalTypeParameter ::= Ident ClassBound {InterfaceBound}.
248 
249         scanIdentifier();
250         String name = identifier.intern(); // FIXME: is this o.k.?
251 
252         ListOfTypes bounds = new ListOfTypes(8);
253 
254         // ClassBound ::= ":" [FieldTypeSignature].
255         expect(':');
256         if (symbol == 'L' || symbol == '[' || symbol == 'T') {
257             bounds.add(parseFieldTypeSignature());
258         }
259 
260         while (symbol == ':') {
261             // InterfaceBound ::= ":" FieldTypeSignature.
262             scanSymbol();
263             bounds.add(parseFieldTypeSignature());
264         }
265 
266         return new ImplForVariable<GenericDeclaration>(genericDecl, name, bounds);
267     }
268 
parseFieldTypeSignature()269     Type parseFieldTypeSignature() {
270         // FieldTypeSignature ::= ClassTypeSignature | ArrayTypeSignature
271         //         | TypeVariableSignature.
272 
273         switch (symbol) {
274         case 'L':
275             return parseClassTypeSignature();
276         case '[':
277             // ArrayTypeSignature ::= "[" TypSignature.
278             scanSymbol();
279             return new ImplForArray(parseTypeSignature());
280         case 'T':
281             return parseTypeVariableSignature();
282         default:
283             throw new GenericSignatureFormatError();
284         }
285     }
286 
parseClassTypeSignature()287     Type parseClassTypeSignature() {
288         // ClassTypeSignature ::= "L" {Ident "/"} Ident
289         //         OptTypeArguments {"." Ident OptTypeArguments} ";".
290 
291         expect('L');
292 
293         StringBuilder qualIdent = new StringBuilder();
294         scanIdentifier();
295         while (symbol == '/') {
296             scanSymbol();
297             qualIdent.append(identifier).append(".");
298             scanIdentifier();
299         }
300 
301         qualIdent.append(this.identifier);
302 
303         ListOfTypes typeArgs = parseOptTypeArguments();
304         ImplForType parentType =
305                 new ImplForType(null, qualIdent.toString(), typeArgs, loader);
306         ImplForType type = parentType;
307 
308         while (symbol == '.') {
309             // Deal with Member Classes:
310             scanSymbol();
311             scanIdentifier();
312             qualIdent.append("$").append(identifier); // FIXME: is "$" correct?
313             typeArgs = parseOptTypeArguments();
314             type = new ImplForType(parentType, qualIdent.toString(), typeArgs,
315                     loader);
316         }
317 
318         expect(';');
319 
320         return type;
321     }
322 
parseOptTypeArguments()323     ListOfTypes parseOptTypeArguments() {
324         // OptTypeArguments ::= "<" TypeArgument {TypeArgument} ">".
325 
326         ListOfTypes typeArgs = new ListOfTypes(8);
327         if (symbol == '<') {
328             scanSymbol();
329 
330             typeArgs.add(parseTypeArgument());
331             while ((symbol != '>') && (symbol > 0)) {
332                 typeArgs.add(parseTypeArgument());
333             }
334             expect('>');
335         }
336         return typeArgs;
337     }
338 
parseTypeArgument()339     Type parseTypeArgument() {
340         // TypeArgument ::= (["+" | "-"] FieldTypeSignature) | "*".
341         ListOfTypes extendsBound = new ListOfTypes(1);
342         ListOfTypes superBound = new ListOfTypes(1);
343         if (symbol == '*') {
344             scanSymbol();
345             extendsBound.add(Object.class);
346             return new ImplForWildcard(extendsBound, superBound);
347         }
348         else if (symbol == '+') {
349             scanSymbol();
350             extendsBound.add(parseFieldTypeSignature());
351             return new ImplForWildcard(extendsBound, superBound);
352         }
353         else if (symbol == '-') {
354             scanSymbol();
355             superBound.add(parseFieldTypeSignature());
356             extendsBound.add(Object.class);
357             return new ImplForWildcard(extendsBound, superBound);
358         }
359         else {
360             return parseFieldTypeSignature();
361         }
362     }
363 
parseTypeVariableSignature()364     ImplForVariable<GenericDeclaration> parseTypeVariableSignature() {
365         // TypeVariableSignature ::= "T" Ident ";".
366         expect('T');
367         scanIdentifier();
368         expect(';');
369         // Reference to type variable:
370         // Note: we don't know the declaring GenericDeclaration yet.
371         return new ImplForVariable<GenericDeclaration>(genericDecl, identifier);
372     }
373 
parseTypeSignature()374     Type parseTypeSignature() {
375         switch (symbol) {
376         case 'B': scanSymbol(); return byte.class;
377         case 'C': scanSymbol(); return char.class;
378         case 'D': scanSymbol(); return double.class;
379         case 'F': scanSymbol(); return float.class;
380         case 'I': scanSymbol(); return int.class;
381         case 'J': scanSymbol(); return long.class;
382         case 'S': scanSymbol(); return short.class;
383         case 'Z': scanSymbol(); return boolean.class;
384         default:
385             // Not an elementary type, but a FieldTypeSignature.
386             return parseFieldTypeSignature();
387         }
388     }
389 
390     /**
391      * @param rawExceptionTypes the non-generic exceptions. This is necessary
392      *     because the signature may omit the exceptions when none are generic.
393      *     May be null for methods that declare no exceptions.
394      */
parseMethodTypeSignature(Class<?>[] rawExceptionTypes)395     void parseMethodTypeSignature(Class<?>[] rawExceptionTypes) {
396         // MethodTypeSignature ::= [FormalTypeParameters]
397         //         "(" {TypeSignature} ")" ReturnType {ThrowsSignature}.
398 
399         parseOptFormalTypeParameters();
400 
401         parameterTypes = new ListOfTypes(16);
402         expect('(');
403         while (symbol != ')' && (symbol > 0)) {
404             parameterTypes.add(parseTypeSignature());
405         }
406         expect(')');
407 
408         returnType = parseReturnType();
409 
410         if (symbol == '^') {
411             exceptionTypes = new ListOfTypes(8);
412             do {
413                 scanSymbol();
414 
415                 // ThrowsSignature ::= ("^" ClassTypeSignature) |
416                 //     ("^" TypeVariableSignature).
417                 if (symbol == 'T') {
418                     exceptionTypes.add(parseTypeVariableSignature());
419                 } else {
420                     exceptionTypes.add(parseClassTypeSignature());
421                 }
422             } while (symbol == '^');
423         } else if (rawExceptionTypes != null) {
424             exceptionTypes = new ListOfTypes(rawExceptionTypes);
425         } else {
426             exceptionTypes = new ListOfTypes(0);
427         }
428     }
429 
parseReturnType()430     Type parseReturnType() {
431         // ReturnType ::= TypeSignature | "V".
432         if (symbol != 'V') { return parseTypeSignature(); }
433         else { scanSymbol(); return void.class; }
434     }
435 
436 
437     //
438     // Scanner:
439     //
440 
scanSymbol()441     void scanSymbol() {
442         if (!eof) {
443             if (pos < buffer.length) {
444                 symbol = buffer[pos];
445                 pos++;
446             } else {
447                 symbol = 0;
448                 eof = true;
449             }
450         } else {
451             throw new GenericSignatureFormatError();
452         }
453     }
454 
expect(char c)455     void expect(char c) {
456         if (symbol == c) {
457             scanSymbol();
458         } else {
459             throw new GenericSignatureFormatError();
460         }
461     }
462 
isStopSymbol(char ch)463     boolean isStopSymbol(char ch) {
464         switch (ch) {
465         case ':':
466         case '/':
467         case ';':
468         case '<':
469         case '.':
470             return true;
471         }
472         return false;
473     }
474 
475     // PRE: symbol is the first char of the identifier.
476     // POST: symbol = the next symbol AFTER the identifier.
scanIdentifier()477     void scanIdentifier() {
478         if (!eof) {
479             StringBuilder identBuf = new StringBuilder(32);
480             if (!isStopSymbol(symbol)) {
481                 identBuf.append(symbol);
482                 do {
483                     char ch = buffer[pos];
484                     if ((ch >= 'a') && (ch <= 'z') || (ch >= 'A') && (ch <= 'Z')
485                             || !isStopSymbol(ch)) {
486                         identBuf.append(buffer[pos]);
487                         pos++;
488                     } else {
489                         identifier = identBuf.toString();
490                         scanSymbol();
491                         return;
492                     }
493                 } while (pos != buffer.length);
494                 identifier = identBuf.toString();
495                 symbol = 0;
496                 eof = true;
497             } else {
498                 // Ident starts with incorrect char.
499                 symbol = 0;
500                 eof = true;
501                 throw new GenericSignatureFormatError();
502             }
503         } else {
504             throw new GenericSignatureFormatError();
505         }
506     }
507 
508 }
509