Home | History | Annotate | Download | only in util
      1 /*
      2  * ProGuard -- shrinking, optimization, obfuscation, and preverification
      3  *             of Java bytecode.
      4  *
      5  * Copyright (c) 2002-2014 Eric Lafortune (eric (at) graphics.cornell.edu)
      6  *
      7  * This program is free software; you can redistribute it and/or modify it
      8  * under the terms of the GNU General Public License as published by the Free
      9  * Software Foundation; either version 2 of the License, or (at your option)
     10  * any later version.
     11  *
     12  * This program is distributed in the hope that it will be useful, but WITHOUT
     13  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
     14  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
     15  * more details.
     16  *
     17  * You should have received a copy of the GNU General Public License along
     18  * with this program; if not, write to the Free Software Foundation, Inc.,
     19  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
     20  */
     21 package proguard.classfile.util;
     22 
     23 import proguard.classfile.ClassConstants;
     24 
     25 
     26 /**
     27  * An <code>InternalTypeEnumeration</code> provides an enumeration of all
     28  * parameter types listed in a given internal method descriptor or signature.
     29  * The signature can also be a class signature. The return type of a method
     30  * descriptor can be retrieved separately.
     31  *
     32  * @author Eric Lafortune
     33  */
     34 public class InternalTypeEnumeration
     35 {
     36     private String descriptor;
     37     private int    firstIndex;
     38     private int    lastIndex;
     39     private int    index;
     40 
     41 
     42     /**
     43      * Creates a new InternalTypeEnumeration for the given method descriptor.
     44      */
     45     public InternalTypeEnumeration(String descriptor)
     46     {
     47         this.descriptor = descriptor;
     48         this.firstIndex = descriptor.indexOf(ClassConstants.METHOD_ARGUMENTS_OPEN);
     49         this.lastIndex  = descriptor.indexOf(ClassConstants.METHOD_ARGUMENTS_CLOSE);
     50         this.index      = firstIndex + 1;
     51 
     52         if (lastIndex < 0)
     53         {
     54             lastIndex = descriptor.length();
     55         }
     56     }
     57 
     58 
     59     /**
     60      * Returns whether the type is a method signature.
     61      */
     62     public boolean isMethodSignature()
     63     {
     64         return firstIndex >= 0;
     65     }
     66 
     67 
     68     /**
     69      * Returns the formal type parameters from the descriptor, assuming it's a
     70      * method descriptor.
     71      */
     72     public String formalTypeParameters()
     73     {
     74         return descriptor.substring(0, firstIndex);
     75     }
     76 
     77 
     78     /**
     79      * Returns whether the enumeration can provide more types from the method
     80      * descriptor.
     81      */
     82     public boolean hasMoreTypes()
     83     {
     84         return index < lastIndex;
     85     }
     86 
     87 
     88     /**
     89      * Returns the next type from the method descriptor.
     90      */
     91     public String nextType()
     92     {
     93         int startIndex = index;
     94 
     95         skipArray();
     96 
     97         char c = descriptor.charAt(index++);
     98         switch (c)
     99         {
    100             case ClassConstants.TYPE_CLASS_START:
    101             case ClassConstants.TYPE_GENERIC_VARIABLE_START:
    102             {
    103                 skipClass();
    104                 break;
    105             }
    106             case ClassConstants.TYPE_GENERIC_START:
    107             {
    108                 skipGeneric();
    109                 break;
    110             }
    111         }
    112 
    113         return descriptor.substring(startIndex, index);
    114     }
    115 
    116 
    117     /**
    118      * Returns the return type from the descriptor, assuming it's a method
    119      * descriptor.
    120      */
    121     public String returnType()
    122     {
    123         return descriptor.substring(lastIndex + 1);
    124     }
    125 
    126 
    127     // Small utility methods.
    128 
    129     private void skipArray()
    130     {
    131         while (descriptor.charAt(index) == ClassConstants.TYPE_ARRAY)
    132         {
    133             index++;
    134         }
    135     }
    136 
    137 
    138     private void skipClass()
    139     {
    140         while (true)
    141         {
    142             char c = descriptor.charAt(index++);
    143             switch (c)
    144             {
    145                 case ClassConstants.TYPE_GENERIC_START:
    146                     skipGeneric();
    147                     break;
    148 
    149                 case ClassConstants.TYPE_CLASS_END:
    150                     return;
    151             }
    152         }
    153     }
    154 
    155 
    156     private void skipGeneric()
    157     {
    158         int nestingLevel = 1;
    159 
    160         do
    161         {
    162             char c = descriptor.charAt(index++);
    163             switch (c)
    164             {
    165                 case ClassConstants.TYPE_GENERIC_START:
    166                     nestingLevel++;
    167                     break;
    168 
    169                 case ClassConstants.TYPE_GENERIC_END:
    170                     nestingLevel--;
    171                     break;
    172             }
    173         }
    174         while (nestingLevel > 0);
    175     }
    176 
    177 
    178     /**
    179      * A main method for testing the type enumeration.
    180      */
    181     public static void main(String[] args)
    182     {
    183         try
    184         {
    185             for (int index = 0; index < args.length; index++)
    186             {
    187                 String descriptor = args[index];
    188 
    189                 System.out.println("Descriptor ["+descriptor+"]");
    190                 InternalTypeEnumeration enumeration = new InternalTypeEnumeration(descriptor);
    191 
    192                 if (enumeration.firstIndex >= 0)
    193                 {
    194                     System.out.println("  Formal type parameters ["+enumeration.formalTypeParameters()+"]");
    195                 }
    196 
    197                 while (enumeration.hasMoreTypes())
    198                 {
    199                     System.out.println("  Type ["+enumeration.nextType()+"]");
    200                 }
    201 
    202                 if (enumeration.lastIndex < descriptor.length())
    203                 {
    204                     System.out.println("  Return type ["+enumeration.returnType()+"]");
    205                 }
    206             }
    207         }
    208         catch (Exception ex)
    209         {
    210             ex.printStackTrace();
    211         }
    212     }
    213 }
    214