Home | History | Annotate | Download | only in sourcer
      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 com.android.mkstubs.sourcer;
     18 
     19 import com.android.mkstubs.Main;
     20 
     21 import org.objectweb.asm.Type;
     22 import org.objectweb.asm.signature.SignatureReader;
     23 import org.objectweb.asm.signature.SignatureVisitor;
     24 import org.objectweb.asm.signature.SignatureWriter;
     25 
     26 import java.util.ArrayList;
     27 
     28 /**
     29  * A signature visitor that can be used to generate Java source corresponding to
     30  * various types of signatures.
     31  * <p/>
     32  * Terminology: a "signature" is a type descriptor for generics. There are different types
     33  * of signatures depending on the context where they are used, e.g. method declarations,
     34  * method parameters, class declarations, etc..
     35  * <p/>
     36  * Note: most of the implementation is a duplicate of ASM's SignatureWriter with some
     37  * slight variations.
     38  * <p/>
     39  * Note: When processing a method's signature, the signature order is the reverse of the source
     40  * order, e.g. the signature is written as "(parameters)return-type" where we want to generate
     41  * "return-type method-name (parameters)". To handle this case, the return-type and parameters
     42  * are <em>not</em> output directly but are instead accumulated in internal variables that you can
     43  * get later using {@link #getReturnType()}, {@link #getParameters()}, {@link #getSuperClass()}
     44  * and {@link #formalsToString()}.
     45  */
     46 class SignatureSourcer extends SignatureVisitor {
     47 
     48     /**
     49      * Buffer used to construct the signature.
     50      */
     51     private final StringBuilder mBuf = new StringBuilder();
     52 
     53     /**
     54      * Buffer used to construct the formals signature.
     55      */
     56     private final StringBuilder mFormalsBuf = new StringBuilder();
     57 
     58     /**
     59      * Indicates if the signature is currently processing formal type parameters.
     60      */
     61     private boolean mWritingFormals;
     62 
     63     /**
     64      * Stack used to keep track of class types that have arguments. Each element
     65      * of this stack is a boolean encoded in one bit. The top of the stack is
     66      * the lowest order bit. Pushing false = *2, pushing true = *2+1, popping =
     67      * /2.
     68      */
     69     private int mArgumentStack;
     70 
     71     /**
     72      * {@link SignatureSourcer} generated when parsing the return type of <em>this</em>
     73      * signature. Initially null.
     74      */
     75     private SignatureSourcer mReturnType;
     76 
     77     /**
     78      * {@link SignatureSourcer} generated when parsing the super class of <em>this</em>
     79      * signature. Initially null.
     80      */
     81     private SignatureSourcer mSuperClass;
     82 
     83     /**
     84      * {@link SignatureSourcer}s for each parameters generated when parsing the method parameters
     85      * of <em>this</em> signature. Initially empty but not null.
     86      */
     87     private ArrayList<SignatureSourcer> mParameters = new ArrayList<>();
     88 
     89 
     90 
     91     /**
     92      * Constructs a new {@link SignatureWriter} object.
     93      */
     94     public SignatureSourcer() {
     95         super(Main.ASM_VERSION);
     96     }
     97 
     98     private StringBuilder getBuf() {
     99         if (mWritingFormals) {
    100             return mFormalsBuf;
    101         } else {
    102             return mBuf;
    103         }
    104     }
    105 
    106     /**
    107      * Contains the whole signature type when called by
    108      * {@link SignatureReader#acceptType(SignatureVisitor)} or just the formals if
    109      * called by {@link SignatureReader#accept(SignatureVisitor)}.
    110      */
    111     @Override
    112     public String toString() {
    113         return mBuf.toString();
    114     }
    115 
    116     /**
    117      * Will be non-null if a return type was processed
    118      * by {@link SignatureReader#accept(SignatureVisitor)}
    119      */
    120     public SignatureSourcer getReturnType() {
    121         return mReturnType;
    122     }
    123 
    124     /**
    125      * Will be non-empty if a parameters were processed
    126      * by {@link SignatureReader#accept(SignatureVisitor)}
    127      */
    128     public ArrayList<SignatureSourcer> getParameters() {
    129         return mParameters;
    130     }
    131 
    132     /**
    133      * True if the signature contains formal type parameters, which are available
    134      * via {@link #formalsToString()} after calling {@link SignatureReader#accept(SignatureVisitor)}
    135      */
    136     public boolean hasFormalsContent() {
    137         return mFormalsBuf.length() > 0;
    138     }
    139 
    140     public String formalsToString() {
    141         return mFormalsBuf.toString();
    142     }
    143 
    144     /**
    145      * Will be non-null if a super class was processed
    146      * by {@link SignatureReader#accept(SignatureVisitor)}
    147      */
    148     public SignatureSourcer getSuperClass() {
    149         return mSuperClass;
    150     }
    151 
    152     // ------------------------------------------------------------------------
    153     // Implementation of the SignatureVisitor interface
    154     // ------------------------------------------------------------------------
    155 
    156     @Override
    157     public void visitFormalTypeParameter(final String name) {
    158         if (!mWritingFormals) {
    159             mWritingFormals = true;
    160             getBuf().append('<');
    161         } else {
    162             getBuf().append(", ");
    163         }
    164         getBuf().append(name);
    165         getBuf().append(" extends ");
    166     }
    167 
    168     @Override
    169     public SignatureVisitor visitClassBound() {
    170         // we don't differentiate between visiting a sub class or interface type
    171         return this;
    172     }
    173 
    174     @Override
    175     public SignatureVisitor visitInterfaceBound() {
    176         // we don't differentiate between visiting a sub class or interface type
    177         return this;
    178     }
    179 
    180     @Override
    181     public SignatureVisitor visitSuperclass() {
    182         endFormals();
    183         SignatureSourcer sourcer = new SignatureSourcer();
    184         assert mSuperClass == null;
    185         mSuperClass = sourcer;
    186         return sourcer;
    187     }
    188 
    189     @Override
    190     public SignatureVisitor visitInterface() {
    191         return this;
    192     }
    193 
    194     @Override
    195     public SignatureVisitor visitParameterType() {
    196         endFormals();
    197         SignatureSourcer sourcer = new SignatureSourcer();
    198         mParameters.add(sourcer);
    199         return sourcer;
    200     }
    201 
    202     @Override
    203     public SignatureVisitor visitReturnType() {
    204         endFormals();
    205         SignatureSourcer sourcer = new SignatureSourcer();
    206         assert mReturnType == null;
    207         mReturnType = sourcer;
    208         return sourcer;
    209     }
    210 
    211     @Override
    212     public SignatureVisitor visitExceptionType() {
    213         getBuf().append('^');
    214         return this;
    215     }
    216 
    217     @Override
    218     public void visitBaseType(final char descriptor) {
    219         getBuf().append(Type.getType(Character.toString(descriptor)).getClassName());
    220     }
    221 
    222     @Override
    223     public void visitTypeVariable(final String name) {
    224         getBuf().append(name.replace('/', '.'));
    225     }
    226 
    227     @Override
    228     public SignatureVisitor visitArrayType() {
    229         getBuf().append('[');
    230         return this;
    231     }
    232 
    233     @Override
    234     public void visitClassType(final String name) {
    235         getBuf().append(name.replace('/', '.'));
    236         mArgumentStack *= 2;
    237     }
    238 
    239     @Override
    240     public void visitInnerClassType(final String name) {
    241         endArguments();
    242         getBuf().append('.');
    243         getBuf().append(name.replace('/', '.'));
    244         mArgumentStack *= 2;
    245     }
    246 
    247     @Override
    248     public void visitTypeArgument() {
    249         if (mArgumentStack % 2 == 0) {
    250             ++mArgumentStack;
    251             getBuf().append('<');
    252         } else {
    253             getBuf().append(", ");
    254         }
    255         getBuf().append('*');
    256     }
    257 
    258     @Override
    259     public SignatureVisitor visitTypeArgument(final char wildcard) {
    260         if (mArgumentStack % 2 == 0) {
    261             ++mArgumentStack;
    262             getBuf().append('<');
    263         } else {
    264             getBuf().append(", ");
    265         }
    266         if (wildcard != '=') {
    267             if (wildcard == '+') {
    268                 getBuf().append("? extends ");
    269             } else if (wildcard == '-') {
    270                 getBuf().append("? super ");
    271             } else {
    272                 // can this happen?
    273                 getBuf().append(wildcard);
    274             }
    275         }
    276         return this;
    277     }
    278 
    279     @Override
    280     public void visitEnd() {
    281         endArguments();
    282     }
    283 
    284     // ------------------------------------------------------------------------
    285     // Utility methods
    286     // ------------------------------------------------------------------------
    287 
    288     /**
    289      * Ends the formal type parameters section of the signature.
    290      */
    291     private void endFormals() {
    292         if (mWritingFormals) {
    293             getBuf().append('>');
    294             mWritingFormals = false;
    295         }
    296     }
    297 
    298     /**
    299      * Ends the type arguments of a class or inner class type.
    300      */
    301     private void endArguments() {
    302         if (mArgumentStack % 2 != 0) {
    303             getBuf().append('>');
    304         }
    305         mArgumentStack /= 2;
    306     }
    307 }
    308