View Javadoc

    1   /*
    2   $Id: ClassHelper.java,v 1.4 2006/01/19 00:06:51 blackdrag Exp $ created on 25.10.2005
    3
    4   Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
    5
    6   Redistribution and use of this software and associated documentation
    7   ("Software"), with or without modification, are permitted provided
    8   that the following conditions are met:
    9
    10  1. Redistributions of source code must retain copyright
    11     statements and notices.  Redistributions must also contain a
    12     copy of this document.
    13
    14  2. Redistributions in binary form must reproduce the
    15     above copyright notice, this list of conditions and the
    16     following disclaimer in the documentation and/or other
    17     materials provided with the distribution.
    18
    19  3. The name "groovy" must not be used to endorse or promote
    20     products derived from this Software without prior written
    21     permission of The Codehaus.  For written permission,
    22     please contact info@codehaus.org.
    23
    24  4. Products derived from this Software may not be called "groovy"
    25     nor may "groovy" appear in their names without prior written
    26     permission of The Codehaus. "groovy" is a registered
    27     trademark of The Codehaus.
    28
    29  5. Due credit should be given to The Codehaus -
    30     http://groovy.codehaus.org/
    31
    32  THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
    33  ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
    34  NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
    35  FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
    36  THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
    37  INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
    38  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
    39  SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
    40  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
    41  STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
    42  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
    43  OF THE POSSIBILITY OF SUCH DAMAGE.
    44  */
    45
    46  package org.codehaus.groovy.ast;
    47
    48  import groovy.lang.Closure;
    49  import groovy.lang.GString;
    50  import groovy.lang.Range;
    51  import groovy.lang.Reference;
    52  import groovy.lang.Script;
    53
    54  import java.math.BigDecimal;
    55  import java.math.BigInteger;
    56  import java.util.List;
    57  import java.util.Map;
    58  import java.util.regex.Pattern;
    59
    60  import org.objectweb.asm.Opcodes;
    61
    62  /***
    63   * This class is a Helper for ClassNode and classes handling ClassNodes.
    64   * It does contain a set of predefined ClassNodes for the most used
    65   * types and some code for cached ClassNode creation and basic
    66   * ClassNode handling
    67   *
    68   * @author Jochen Theodorou
    69   */
    70  public class ClassHelper {
    71
    72
    73      private static String[] names = new String[] {
    74          boolean.class.getName(),    char.class.getName(),
    75          byte.class.getName(),       short.class.getName(),
    76          int.class.getName(),        long.class.getName(),
    77          double.class.getName(),     float.class.getName(),
    78          Object.class.getName(),     Void.TYPE.getName(),
    79          Closure.class.getName(),    GString.class.getName(),
    80          List.class.getName(),       Map.class.getName(),
    81          Range.class.getName(),      Pattern.class.getName(),
    82          Script.class.getName(),     String.class.getName(),
    83          Boolean.class.getName(),    Character.class.getName(),
    84          Byte.class.getName(),       Short.class.getName(),
    85          Integer.class.getName(),    Long.class.getName(),
    86          Double.class.getName(),     Float.class.getName(),
    87          BigDecimal.class.getName(), BigInteger.class.getName(),
    88          Void.class.getName(),       Reference.class.getName()
    89      };
    90
    91      private static Class[] classes = new Class[] {
    92          Object.class, Boolean.TYPE, Character.TYPE, Byte.TYPE, Short.TYPE,
    93          Integer.TYPE, Long.TYPE, Double.TYPE, Float.TYPE, Void.TYPE,
    94          Closure.class, GString.class, List.class, Map.class, Range.class,
    95          Pattern.class, Script.class, String.class,  Boolean.class,
    96          Character.class, Byte.class, Short.class, Integer.class, Long.class,
    97          Double.class, Float.class, BigDecimal.class, BigInteger.class, Void.class,
    98          Reference.class
    99      };
    100
    101     public static final ClassNode
    102         DYNAMIC_TYPE = new ClassNode(Object.class),  OBJECT_TYPE = DYNAMIC_TYPE,
    103         VOID_TYPE = new ClassNode(Void.TYPE),        CLOSURE_TYPE = new ClassNode(Closure.class),
    104         GSTRING_TYPE = new ClassNode(GString.class), LIST_TYPE = new ClassNode(List.class),
    105         MAP_TYPE = new ClassNode(Map.class),         RANGE_TYPE = new ClassNode(Range.class),
    106         PATTERN_TYPE = new ClassNode(Pattern.class), STRING_TYPE = new ClassNode(String.class),
    107         SCRIPT_TYPE = new ClassNode(Script.class),   REFERENCE_TYPE = new ClassNode(Reference.class),
    108
    109         boolean_TYPE = new ClassNode(boolean.class),     char_TYPE = new ClassNode(char.class),
    110         byte_TYPE = new ClassNode(byte.class),           int_TYPE = new ClassNode(int.class),
    111         long_TYPE = new ClassNode(long.class),           short_TYPE = new ClassNode(short.class),
    112         double_TYPE = new ClassNode(double.class),       float_TYPE = new ClassNode(float.class),
    113         Byte_TYPE = new ClassNode(Byte.class),           Short_TYPE = new ClassNode(Short.class),
    114         Integer_TYPE = new ClassNode(Integer.class),     Long_TYPE = new ClassNode(Long.class),
    115         Character_TYPE = new ClassNode(Character.class), Float_TYPE = new ClassNode(Float.class),
    116         Double_TYPE = new ClassNode(Double.class),       Boolean_TYPE = new ClassNode(Boolean.class),
    117         BigInteger_TYPE =  new ClassNode(java.math.BigInteger.class),
    118         BigDecimal_TYPE = new ClassNode(java.math.BigDecimal.class),
    119         void_WRAPPER_TYPE = new ClassNode(Void.class);
    120
    121
    122     private static ClassNode[] types = new ClassNode[] {
    123         OBJECT_TYPE,
    124         boolean_TYPE, char_TYPE, byte_TYPE, short_TYPE,
    125         int_TYPE, long_TYPE, double_TYPE, float_TYPE,
    126         VOID_TYPE, CLOSURE_TYPE, GSTRING_TYPE,
    127         LIST_TYPE, MAP_TYPE, RANGE_TYPE, PATTERN_TYPE,
    128         SCRIPT_TYPE, STRING_TYPE, Boolean_TYPE, Character_TYPE,
    129         Byte_TYPE, Short_TYPE, Integer_TYPE, Long_TYPE,
    130         Double_TYPE, Float_TYPE, BigDecimal_TYPE, BigInteger_TYPE,
    131         void_WRAPPER_TYPE, REFERENCE_TYPE
    132     };
    133
    134
    135     private static ClassNode[] numbers = new ClassNode[] {
    136         char_TYPE, byte_TYPE, short_TYPE, int_TYPE, long_TYPE,
    137         double_TYPE, float_TYPE, Short_TYPE, Byte_TYPE, Character_TYPE,
    138         Integer_TYPE, Float_TYPE, Long_TYPE, Double_TYPE, BigInteger_TYPE,
    139         BigDecimal_TYPE
    140     };
    141
    142     protected static final ClassNode[] EMPTY_TYPE_ARRAY = {};
    143
    144     public static final String OBJECT = "java.lang.Object";
    145
    146
    147     /***
    148      * Creates an array of ClassNodes using an array of classes.
    149      * For each of the given classes a new ClassNode will be
    150      * created
    151      * @see #make(Class)
    152      * @param classes an array of classes used to create the ClassNodes
    153      * @return an array of ClassNodes
    154      */
    155     public static ClassNode[] make(Class[] classes) {
    156     	ClassNode[] cns = new ClassNode[classes.length];
    157     	for (int i=0; i<cns.length; i++) {
    158     		cns[i] = make(classes[i]);
    159     	}
    160
    161     	return cns;
    162     }
    163
    164     /***
    165      * Creates a ClassNode using a given class.
    166      * A new ClassNode object is only created if the class
    167      * is not one of the predefined ones
    168      *
    169      * @param c class used to created the ClassNode
    170      * @return ClassNode instance created from the given class
    171      */
    172     public static ClassNode make(Class c) {
    173         for (int i=0; i<classes.length; i++) {
    174             if (c==classes[i]) return types[i];
    175         }
    176         if (c.isArray()) {
    177             ClassNode cn = make(c.getComponentType());
    178             return cn.makeArray();
    179         }
    180         ClassNode t = new ClassNode(c);
    181         return t;
    182     }
    183
    184     /***
    185      * Creates a ClassNode using a given class.
    186      * Unlike make(String) this method will not use the cache
    187      * to create the ClassNode. This means to ClassNode created
    188      * from this method using the same name will have a different
    189      * reference
    190      *
    191      * @see #make(String)
    192      * @param name of the class the ClassNode is representing
    193      */
    194     public static ClassNode makeWithoutCaching(String name) {
    195         ClassNode cn = new ClassNode(name,Opcodes.ACC_PUBLIC,OBJECT_TYPE);
    196         cn.isPrimaryNode = false;
    197         return cn;
    198     }
    199
    200     /***
    201      * Creates a ClassNode using a given class.
    202      * If the name is one of the predefined ClassNodes then the
    203      * corresponding ClassNode instance will be returned. If the
    204      * is null of of length 0 the dynamic type is returned
    205      *
    206      * @param name of the class the ClassNode is representing
    207      */
    208     public static ClassNode make(String name) {
    209         if (name == null || name.length() == 0) return DYNAMIC_TYPE;
    210
    211         for (int i=0; i<classes.length; i++) {
    212             String cname = classes[i].getName();
    213             if (name.equals(cname)) return types[i];
    214         }
    215         return makeWithoutCaching(name);
    216     }
    217
    218     /***
    219      * Creates a ClassNode containing the wrapper of a ClassNode
    220      * of primitive type. Any ClassNode representing a primitive
    221      * type should be created using the predefined types used in
    222      * class. The method will check the parameter for known
    223      * references of ClassNode representing a primitive type. If
    224      * Reference is found, then a ClassNode will be contained that
    225      * represents the wrapper class. For exmaple for boolean, the
    226      * wrapper class is java.lang.Boolean.
    227      *
    228      * If the parameter is no primitve type, the redirected
    229      * ClassNode will be returned
    230      *
    231      * @see #make(Class)
    232      * @see #make(String)
    233      * @param cn the ClassNode containing a possible primitive type
    234      */
    235     public static ClassNode getWrapper(ClassNode cn) {
    236         cn = cn.redirect();
    237         if (!isPrimitiveType(cn)) return cn;
    238         if (cn==boolean_TYPE) {
    239             return Boolean_TYPE;
    240         } else if (cn==byte_TYPE) {
    241             return Byte_TYPE;
    242         } else if (cn==char_TYPE) {
    243             return Character_TYPE;
    244         } else if (cn==short_TYPE) {
    245             return Short_TYPE;
    246         } else if (cn==int_TYPE) {
    247             return Integer_TYPE;
    248         } else if (cn==long_TYPE) {
    249             return Long_TYPE;
    250         } else if (cn==float_TYPE) {
    251             return Float_TYPE;
    252         } else if (cn==double_TYPE) {
    253             return Double_TYPE;
    254         } else if (cn==VOID_TYPE) {
    255         	return void_WRAPPER_TYPE;
    256         }
    257         else {
    258             return cn;
    259         }
    260     }
    261
    262     /***
    263      * Test to determine if a ClasNode is a primitve type.
    264      * Note: this only works for ClassNodes created using a
    265      * predefined ClassNode
    266      *
    267      * @see #make(Class)
    268      * @see #make(String)
    269      * @param cn the ClassNode containing a possible primitive type
    270      * @return true if the ClassNode is a primitve type
    271      */
    272     public static boolean isPrimitiveType(ClassNode cn) {
    273         return  cn == boolean_TYPE ||
    274                 cn == char_TYPE ||
    275                 cn == byte_TYPE ||
    276                 cn == short_TYPE ||
    277                 cn == int_TYPE ||
    278                 cn == long_TYPE ||
    279                 cn == float_TYPE ||
    280                 cn == double_TYPE ||
    281                 cn == VOID_TYPE;
    282     }
    283
    284     public static ClassNode makeReference() {
    285         return make(Reference.class);
    286     }
    287
    288 }