Home | History | Annotate | Download | only in dex
      1 /*
      2  * Copyright (C) 2009 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 signature.converter.dex;
     18 
     19 import static signature.converter.dex.DexUtil.getClassName;
     20 import static signature.converter.dex.DexUtil.getPackageName;
     21 import signature.model.IClassDefinition;
     22 import signature.model.IClassReference;
     23 import signature.model.IConstructor;
     24 import signature.model.IGenericDeclaration;
     25 import signature.model.IMethod;
     26 import signature.model.ITypeReference;
     27 import signature.model.ITypeVariableDefinition;
     28 import signature.model.ITypeVariableReference;
     29 import signature.model.impl.SigArrayType;
     30 import signature.model.impl.SigParameterizedType;
     31 import signature.model.impl.SigPrimitiveType;
     32 import signature.model.impl.SigTypeVariableDefinition;
     33 import signature.model.impl.SigWildcardType;
     34 import signature.model.impl.Uninitialized;
     35 import signature.model.util.ITypeFactory;
     36 
     37 import java.lang.reflect.GenericSignatureFormatError;
     38 import java.util.ArrayList;
     39 import java.util.List;
     40 
     41 /**
     42  * Implements a parser for the generics signature attribute. Uses a top-down,
     43  * recursive descent parsing approach for the following grammar:
     44  *
     45  * <pre>
     46  * ClassSignature ::=
     47  *     OptFormalTypeParams SuperclassSignature {SuperinterfaceSignature}.
     48  * SuperclassSignature ::= ClassTypeSignature.
     49  * SuperinterfaceSignature ::= ClassTypeSignature.
     50  *
     51  * OptFormalTypeParams ::=
     52  *     ["<" FormalTypeParameter {FormalTypeParameter} ">"].
     53  *
     54  * FormalTypeParameter ::= Ident ClassBound {InterfaceBound}.
     55  * ClassBound ::= ":" [FieldTypeSignature].
     56  * InterfaceBound ::= ":" FieldTypeSignature.
     57  *
     58  * FieldTypeSignature ::=
     59  *     ClassTypeSignature | ArrayTypeSignature | TypeVariableSignature.
     60  * ArrayTypeSignature ::= "[" TypSignature.
     61  *
     62  * ClassTypeSignature ::=
     63  *     "L" {Ident "/"} Ident OptTypeArguments {"." Ident OptTypeArguments} ";".
     64  *
     65  * OptTypeArguments ::= "<" TypeArgument {TypeArgument} ">".
     66  *
     67  * TypeArgument ::= ([WildcardIndicator] FieldTypeSignature) | "*".
     68  * WildcardIndicator ::= "+" | "-".
     69  *
     70  * TypeVariableSignature ::= "T" Ident ";".
     71  *
     72  * TypSignature ::= FieldTypeSignature | BaseType.
     73  * BaseType ::= "B" | "C" | "D" | "F" | "I" | "J" | "S" | "Z".
     74  *
     75  * MethodTypeSignature ::=
     76  *     OptFormalTypeParams "(" {TypeSignature} ")" ReturnType {ThrowsSignature}.
     77  * ThrowsSignature ::= ("^" ClassTypeSignature) | ("^" TypeVariableSignature).
     78  *
     79  * ReturnType ::= TypSignature | VoidDescriptor.
     80  * VoidDescriptor ::= "V".
     81  * </pre>
     82  */
     83 public class GenericSignatureParser {
     84 
     85     public List<ITypeReference> exceptionTypes;
     86     public List<ITypeReference> parameterTypes;
     87     public List<ITypeVariableDefinition> formalTypeParameters;
     88     public ITypeReference returnType;
     89     public ITypeReference fieldType;
     90     public List<ITypeReference> interfaceTypes;
     91     public ITypeReference superclassType;
     92 
     93     private IGenericDeclaration genericDecl;
     94 
     95     /*
     96      * Parser:
     97      */
     98     private char symbol; // 0: eof; else valid term symbol or first char of
     99     // identifier.
    100     private String identifier;
    101 
    102 
    103     /*
    104      * Scanner: eof is private to the scan methods and it's set only when a scan
    105      * is issued at the end of the buffer.
    106      */
    107     private boolean eof;
    108 
    109     private char[] buffer;
    110     private int pos;
    111 
    112     private final ITypeFactory factory;
    113     private final IClassInitializer classFinder;
    114     private boolean parseForField;
    115 
    116 
    117     public GenericSignatureParser(ITypeFactory factory,
    118             IClassInitializer classFinder) {
    119         this.factory = factory;
    120         this.classFinder = classFinder;
    121     }
    122 
    123     private void setInput(IGenericDeclaration genericDecl, String input) {
    124         if (input != null) {
    125             this.genericDecl = genericDecl;
    126             this.buffer = input.toCharArray();
    127             this.eof = false;
    128             scanSymbol();
    129         } else {
    130             this.eof = true;
    131         }
    132     }
    133 
    134     public ITypeReference parseNonGenericType(String typeSignature) {
    135         setInput(null, typeSignature);
    136         ITypeReference type = parsePrimitiveType();
    137         if (type == null) {
    138             type = parseFieldTypeSignature();
    139         }
    140         return type;
    141     }
    142 
    143     public ITypeReference parseNonGenericReturnType(String typeSignature) {
    144         setInput(null, typeSignature);
    145         ITypeReference returnType = parsePrimitiveType();
    146         if (returnType == null) {
    147             returnType = parseReturnType();
    148         }
    149         return returnType;
    150     }
    151 
    152     private ITypeReference parsePrimitiveType() {
    153         switch (symbol) {
    154         case 'B':
    155             scanSymbol();
    156             return SigPrimitiveType.BYTE_TYPE;
    157         case 'C':
    158             scanSymbol();
    159             return SigPrimitiveType.CHAR_TYPE;
    160         case 'D':
    161             scanSymbol();
    162             return SigPrimitiveType.DOUBLE_TYPE;
    163         case 'F':
    164             scanSymbol();
    165             return SigPrimitiveType.FLOAT_TYPE;
    166         case 'I':
    167             scanSymbol();
    168             return SigPrimitiveType.INT_TYPE;
    169         case 'J':
    170             scanSymbol();
    171             return SigPrimitiveType.LONG_TYPE;
    172         case 'S':
    173             scanSymbol();
    174             return SigPrimitiveType.SHORT_TYPE;
    175         case 'Z':
    176             scanSymbol();
    177             return SigPrimitiveType.BOOLEAN_TYPE;
    178         default:
    179             return null;
    180         }
    181     }
    182 
    183     /**
    184      * Parses the generic signature of a class and creates the data structure
    185      * representing the signature.
    186      *
    187      * @param classToProcess
    188      *            the GenericDeclaration calling this method
    189      * @param signature
    190      *            the generic signature of the class
    191      */
    192     public void parseForClass(IClassDefinition classToProcess,
    193             String signature) {
    194         setInput(classToProcess, signature);
    195         if (!eof) {
    196             parseClassSignature();
    197         } else {
    198             throw new IllegalStateException("Generic signature is invalid!");
    199         }
    200     }
    201 
    202     /**
    203      * Parses the generic signature of a method and creates the data structure
    204      * representing the signature.
    205      *
    206      * @param genericDecl
    207      *            the GenericDeclaration calling this method
    208      * @param signature
    209      *            the generic signature of the class
    210      */
    211     public void parseForMethod(IMethod genericDecl, String signature) {
    212         setInput(genericDecl, signature);
    213         if (!eof) {
    214             parseMethodTypeSignature();
    215         } else {
    216             throw new IllegalStateException("Generic signature is invalid!");
    217         }
    218     }
    219 
    220     /**
    221      * Parses the generic signature of a constructor and creates the data
    222      * structure representing the signature.
    223      *
    224      * @param genericDecl
    225      *            the GenericDeclaration calling this method
    226      * @param signature
    227      *            the generic signature of the class
    228      */
    229     public void parseForConstructor(IConstructor genericDecl,
    230             String signature) {
    231         setInput(genericDecl, signature);
    232         if (!eof) {
    233             parseMethodTypeSignature();
    234         } else {
    235             throw new IllegalStateException("Generic signature is invalid!");
    236         }
    237     }
    238 
    239     /**
    240      * Parses the generic signature of a field and creates the data structure
    241      * representing the signature.
    242      *
    243      * @param genericDecl
    244      *            the GenericDeclaration calling this method
    245      * @param signature
    246      *            the generic signature of the class
    247      */
    248     public void parseForField(IClassDefinition genericDecl, String signature) {
    249         parseForField = true;
    250         setInput(genericDecl, signature);
    251         try {
    252             if (!eof) {
    253                 this.fieldType = parseFieldTypeSignature();
    254             } else {
    255                 throw new IllegalStateException(
    256                         "Generic signature is invalid!");
    257             }
    258         } finally {
    259             parseForField = false;
    260         }
    261     }
    262 
    263     private void parseClassSignature() {
    264         // ClassSignature ::=
    265         // OptFormalTypeParameters SuperclassSignature
    266         // {SuperinterfaceSignature}.
    267 
    268         parseOptFormalTypeParameters();
    269 
    270         // SuperclassSignature ::= ClassTypeSignature.
    271         this.superclassType = parseClassTypeSignature();
    272 
    273         interfaceTypes = new ArrayList<ITypeReference>(16);
    274         while (symbol > 0) {
    275             // SuperinterfaceSignature ::= ClassTypeSignature.
    276             interfaceTypes.add(parseClassTypeSignature());
    277         }
    278     }
    279 
    280     private void parseOptFormalTypeParameters() {
    281         // OptFormalTypeParameters ::=
    282         // ["<" FormalTypeParameter {FormalTypeParameter} ">"].
    283 
    284         List<ITypeVariableDefinition> typeParameters =
    285                 new ArrayList<ITypeVariableDefinition>();
    286 
    287         if (symbol == '<') {
    288             scanSymbol();
    289             typeParameters.add(parseFormalTypeParameter());
    290             while ((symbol != '>') && (symbol > 0)) {
    291                 typeParameters.add(parseFormalTypeParameter());
    292             }
    293             expect('>');
    294         }
    295 
    296         formalTypeParameters = typeParameters;
    297     }
    298 
    299     private SigTypeVariableDefinition parseFormalTypeParameter() {
    300         // FormalTypeParameter ::= Ident ClassBound {InterfaceBound}.
    301 
    302         scanIdentifier();
    303         String name = identifier.intern();
    304         SigTypeVariableDefinition typeVariable = factory.getTypeVariable(name,
    305                 genericDecl);
    306 
    307         List<ITypeReference> bounds = new ArrayList<ITypeReference>();
    308 
    309         // ClassBound ::= ":" [FieldTypeSignature].
    310         expect(':');
    311         if (symbol == 'L' || symbol == '[' || symbol == 'T') {
    312             bounds.add(parseFieldTypeSignature());
    313         }
    314 
    315         while (symbol == ':') {
    316             // InterfaceBound ::= ":" FieldTypeSignature.
    317             scanSymbol();
    318             bounds.add(parseFieldTypeSignature());
    319         }
    320         typeVariable.setUpperBounds(bounds);
    321         return typeVariable;
    322     }
    323 
    324     /**
    325      * Returns the generic declaration for the type variable with the specified
    326      * name.
    327      *
    328      * @param variableName
    329      *            the name of the type variable
    330      * @param declaration
    331      *            the declaration to start searching
    332      * @return the declaration which defines the specified type variable
    333      */
    334     private IGenericDeclaration getDeclarationOfTypeVariable(
    335             String variableName, IClassDefinition declaration) {
    336         assert variableName != null;
    337         assert declaration != null;
    338 
    339         if (!Uninitialized.isInitialized(declaration.getTypeParameters())) {
    340             declaration = classFinder.initializeClass(declaration
    341                     .getPackageName(), declaration.getName());
    342         }
    343 
    344         for (ITypeVariableDefinition typeVariable : declaration
    345                 .getTypeParameters()) {
    346             if (variableName.equals(typeVariable.getName())) {
    347                 return declaration;
    348             }
    349         }
    350         return getDeclarationOfTypeVariable(variableName, declaration
    351                 .getDeclaringClass());
    352     }
    353 
    354     private ITypeReference parseFieldTypeSignature() {
    355         // FieldTypeSignature ::= ClassTypeSignature | ArrayTypeSignature
    356         // | TypeVariableSignature.
    357 
    358         switch (symbol) {
    359         case 'L':
    360             return parseClassTypeSignature();
    361         case '[':
    362             // ArrayTypeSignature ::= "[" TypSignature.
    363             scanSymbol();
    364             SigArrayType arrayType = factory.getArrayType(parseTypeSignature());
    365             return arrayType;
    366         case 'T':
    367             return parseTypeVariableSignature();
    368         default:
    369             throw new GenericSignatureFormatError();
    370         }
    371     }
    372 
    373     private ITypeReference parseClassTypeSignature() {
    374         // ClassTypeSignature ::= "L" {Ident "/"} Ident
    375         // OptTypeArguments {"." Ident OptTypeArguments} ";".
    376 
    377         expect('L');
    378 
    379         StringBuilder qualIdent = new StringBuilder("L");
    380         scanIdentifier();
    381         while (symbol == '/') {
    382             scanSymbol();
    383             qualIdent.append(identifier).append("/");
    384             scanIdentifier();
    385         }
    386 
    387         qualIdent.append(this.identifier);
    388 
    389 
    390         List<ITypeReference> typeArgs = parseOptTypeArguments();
    391 
    392         ITypeReference parentType = null;
    393 
    394         String packageName = getPackageName(qualIdent.toString() + ";");
    395         String className = getClassName(qualIdent.toString() + ";");
    396 
    397         if (typeArgs.isEmpty()) {
    398             parentType = factory.getClassReference(packageName, className);
    399         } else {
    400             IClassReference rawType = factory.getClassReference(packageName,
    401                     className);
    402             SigParameterizedType parameterizedType = factory
    403                     .getParameterizedType(null, rawType, typeArgs);
    404             parentType = parameterizedType;
    405         }
    406 
    407         ITypeReference typeToReturn = parentType;
    408 
    409 
    410         // if owner type is a parameterized type, the types are separated by '.'
    411         while (symbol == '.') {
    412             // Deal with Member Classes:
    413             scanSymbol();
    414             scanIdentifier();
    415             qualIdent.append("$").append(identifier);
    416             typeArgs = parseOptTypeArguments();
    417             ITypeReference memberType = null;
    418 
    419             packageName = getPackageName(qualIdent.toString() + ";");
    420             className = getClassName(qualIdent.toString() + ";");
    421 
    422             if (typeArgs.isEmpty()) {
    423                 memberType = factory.getClassReference(packageName, className);
    424             } else {
    425                 IClassReference rawType = factory.getClassReference(
    426                         packageName, className);
    427                 SigParameterizedType parameterizedType = factory
    428                         .getParameterizedType(parentType, rawType, typeArgs);
    429                 memberType = parameterizedType;
    430             }
    431             typeToReturn = memberType;
    432         }
    433 
    434         expect(';');
    435 
    436         return typeToReturn;
    437     }
    438 
    439     private List<ITypeReference> parseOptTypeArguments() {
    440         // OptTypeArguments ::= "<" TypeArgument {TypeArgument} ">".
    441 
    442         List<ITypeReference> typeArgs = new ArrayList<ITypeReference>(8);
    443         if (symbol == '<') {
    444             scanSymbol();
    445 
    446             typeArgs.add(parseTypeArgument());
    447             while ((symbol != '>') && (symbol > 0)) {
    448                 typeArgs.add(parseTypeArgument());
    449             }
    450             expect('>');
    451         }
    452         return typeArgs;
    453     }
    454 
    455     private ITypeReference parseTypeArgument() {
    456         // TypeArgument ::= (["+" | "-"] FieldTypeSignature) | "*".
    457         List<ITypeReference> extendsBound = new ArrayList<ITypeReference>(1);
    458         ITypeReference superBound = null;
    459         if (symbol == '*') {
    460             scanSymbol();
    461             extendsBound.add(factory.getClassReference("java.lang", "Object"));
    462             SigWildcardType wildcardType = factory.getWildcardType(superBound,
    463                     extendsBound);
    464             return wildcardType;
    465         } else if (symbol == '+') {
    466             scanSymbol();
    467             extendsBound.add(parseFieldTypeSignature());
    468             SigWildcardType wildcardType = factory.getWildcardType(superBound,
    469                     extendsBound);
    470             return wildcardType;
    471         } else if (symbol == '-') {
    472             scanSymbol();
    473             superBound = parseFieldTypeSignature();
    474             extendsBound.add(factory.getClassReference("java.lang", "Object"));
    475             SigWildcardType wildcardType = factory.getWildcardType(superBound,
    476                     extendsBound);
    477             return wildcardType;
    478         } else {
    479             return parseFieldTypeSignature();
    480         }
    481     }
    482 
    483     private ITypeVariableReference parseTypeVariableSignature() {
    484         // TypeVariableSignature ::= "T" Ident ";".
    485         expect('T');
    486         scanIdentifier();
    487         expect(';');
    488 
    489         IGenericDeclaration declaration = genericDecl;
    490 
    491         if (!factory.containsTypeVariableDefinition(identifier, declaration)) {
    492             // since a field is not a generic declaration, i need to treat it
    493             // differently.
    494             // the generic declaration
    495             if (parseForField) {
    496                 declaration = getDeclarationOfTypeVariable(identifier,
    497                         (IClassDefinition) genericDecl);
    498             } else {
    499                 declaration = getDeclarationOfTypeVariable(identifier,
    500                         genericDecl.getDeclaringClass());
    501             }
    502             // just create type variable
    503             factory.getTypeVariable(identifier, declaration);
    504         }
    505 
    506         return factory.getTypeVariableReference(identifier, declaration);
    507     }
    508 
    509     private ITypeReference parseTypeSignature() {
    510         switch (symbol) {
    511         case 'B':
    512             scanSymbol();
    513             return SigPrimitiveType.BYTE_TYPE;
    514         case 'C':
    515             scanSymbol();
    516             return SigPrimitiveType.CHAR_TYPE;
    517         case 'D':
    518             scanSymbol();
    519             return SigPrimitiveType.DOUBLE_TYPE;
    520         case 'F':
    521             scanSymbol();
    522             return SigPrimitiveType.FLOAT_TYPE;
    523         case 'I':
    524             scanSymbol();
    525             return SigPrimitiveType.INT_TYPE;
    526         case 'J':
    527             scanSymbol();
    528             return SigPrimitiveType.LONG_TYPE;
    529         case 'S':
    530             scanSymbol();
    531             return SigPrimitiveType.SHORT_TYPE;
    532         case 'Z':
    533             scanSymbol();
    534             return SigPrimitiveType.BOOLEAN_TYPE;
    535         default:
    536             // Not an elementary type, but a FieldTypeSignature.
    537             return parseFieldTypeSignature();
    538         }
    539     }
    540 
    541     private void parseMethodTypeSignature() {
    542         // MethodTypeSignature ::= [FormalTypeParameters]
    543         // "(" {TypeSignature} ")" ReturnType {ThrowsSignature}.
    544 
    545         parseOptFormalTypeParameters();
    546 
    547         parameterTypes = new ArrayList<ITypeReference>(16);
    548         expect('(');
    549         while (symbol != ')' && (symbol > 0)) {
    550             parameterTypes.add(parseTypeSignature());
    551         }
    552         expect(')');
    553 
    554         returnType = parseReturnType();
    555 
    556         exceptionTypes = new ArrayList<ITypeReference>(8);
    557         while (symbol == '^') {
    558             scanSymbol();
    559 
    560             // ThrowsSignature ::= ("^" ClassTypeSignature) |
    561             // ("^" TypeVariableSignature).
    562             if (symbol == 'T') {
    563                 exceptionTypes.add(parseTypeVariableSignature());
    564             } else {
    565                 exceptionTypes.add(parseClassTypeSignature());
    566             }
    567         }
    568     }
    569 
    570     private ITypeReference parseReturnType() {
    571         // ReturnType ::= TypeSignature | "V".
    572         if (symbol != 'V') {
    573             return parseTypeSignature();
    574         } else {
    575             scanSymbol();
    576             return SigPrimitiveType.VOID_TYPE;
    577         }
    578     }
    579 
    580 
    581     //
    582     // Scanner:
    583     //
    584 
    585     private void scanSymbol() {
    586         if (!eof) {
    587             if (pos < buffer.length) {
    588                 symbol = buffer[pos];
    589                 pos++;
    590             } else {
    591                 symbol = 0;
    592                 eof = true;
    593             }
    594         } else {
    595             throw new GenericSignatureFormatError();
    596         }
    597     }
    598 
    599     private void expect(char c) {
    600         if (symbol == c) {
    601             scanSymbol();
    602         } else {
    603             throw new GenericSignatureFormatError();
    604         }
    605     }
    606 
    607     private boolean isStopSymbol(char ch) {
    608         switch (ch) {
    609         case ':':
    610         case '/':
    611         case ';':
    612         case '<':
    613         case '.':
    614             return true;
    615         }
    616         return false;
    617     }
    618 
    619     // PRE: symbol is the first char of the identifier.
    620     // POST: symbol = the next symbol AFTER the identifier.
    621     private void scanIdentifier() {
    622         if (!eof) {
    623             StringBuilder identBuf = new StringBuilder(32);
    624             if (!isStopSymbol(symbol)) {
    625                 identBuf.append(symbol);
    626                 do {
    627                     char ch = buffer[pos];
    628                     if ((ch >= 'a') && (ch <= 'z') || (ch >= 'A')
    629                             && (ch <= 'Z') || !isStopSymbol(ch)) {
    630                         identBuf.append(buffer[pos]);
    631                         pos++;
    632                     } else {
    633                         identifier = identBuf.toString();
    634                         scanSymbol();
    635                         return;
    636                     }
    637                 } while (pos != buffer.length);
    638                 identifier = identBuf.toString();
    639                 symbol = 0;
    640                 eof = true;
    641             } else {
    642                 // Ident starts with incorrect char.
    643                 symbol = 0;
    644                 eof = true;
    645                 throw new GenericSignatureFormatError();
    646             }
    647         } else {
    648             throw new GenericSignatureFormatError();
    649         }
    650     }
    651 }
    652