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