Home | History | Annotate | Download | only in reflect
      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 
    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