GenericSignatureParser.java revision a6e22fc9b70ebe39abd716ce37450bda935c0fb8
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
17package libcore.reflect;
18
19import java.lang.reflect.Constructor;
20import java.lang.reflect.GenericDeclaration;
21import java.lang.reflect.GenericSignatureFormatError;
22import java.lang.reflect.Method;
23import java.lang.reflect.Type;
24import java.lang.reflect.TypeVariable;
25import 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 */
68public 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
100    public GenericSignatureParser(ClassLoader loader) {
101        this.loader = loader;
102    }
103
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     */
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     */
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     */
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     */
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
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
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
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
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
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
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
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
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
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     */
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
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
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
469    void expect(char c) {
470        if (symbol == c) {
471            scanSymbol();
472        } else {
473            throw new GenericSignatureFormatError();
474        }
475    }
476
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.
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