blob: a9c04d5f5164927c433ebb390073e6a9de6091ec [file] [log] [blame]
/*
* Copyright 2003-2007 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.codehaus.groovy.ast;
import groovy.lang.Closure;
import groovy.lang.GString;
import groovy.lang.MetaClass;
import groovy.lang.Range;
import groovy.lang.Reference;
import groovy.lang.Script;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;
import org.codehaus.groovy.runtime.GeneratedClosure;
import org.objectweb.asm.Opcodes;
/**
* This class is a Helper for ClassNode and classes handling ClassNodes.
* It does contain a set of predefined ClassNodes for the most used
* types and some code for cached ClassNode creation and basic
* ClassNode handling
*
* @author Jochen Theodorou
*/
public class ClassHelper {
private static final Class[] classes = new Class[] {
Object.class, Boolean.TYPE, Character.TYPE, Byte.TYPE, Short.TYPE,
Integer.TYPE, Long.TYPE, Double.TYPE, Float.TYPE, Void.TYPE,
Closure.class, GString.class, List.class, Map.class, Range.class,
Pattern.class, Script.class, String.class, Boolean.class,
Character.class, Byte.class, Short.class, Integer.class, Long.class,
Double.class, Float.class, BigDecimal.class, BigInteger.class, Void.class,
Reference.class, Class.class, MetaClass.class,
};
private static final String[] primitiveClassNames = new String[] {
"", "boolean", "char", "byte", "short",
"int", "long", "double", "float", "void"
};
public static final ClassNode
DYNAMIC_TYPE = new ClassNode(Object.class), OBJECT_TYPE = DYNAMIC_TYPE,
VOID_TYPE = new ClassNode(Void.TYPE), CLOSURE_TYPE = new ClassNode(Closure.class),
GSTRING_TYPE = new ClassNode(GString.class), LIST_TYPE = new ClassNode(List.class),
MAP_TYPE = new ClassNode(Map.class), RANGE_TYPE = new ClassNode(Range.class),
PATTERN_TYPE = new ClassNode(Pattern.class), STRING_TYPE = new ClassNode(String.class),
SCRIPT_TYPE = new ClassNode(Script.class), REFERENCE_TYPE = new ClassNode(Reference.class),
boolean_TYPE = new ClassNode(boolean.class), char_TYPE = new ClassNode(char.class),
byte_TYPE = new ClassNode(byte.class), int_TYPE = new ClassNode(int.class),
long_TYPE = new ClassNode(long.class), short_TYPE = new ClassNode(short.class),
double_TYPE = new ClassNode(double.class), float_TYPE = new ClassNode(float.class),
Byte_TYPE = new ClassNode(Byte.class), Short_TYPE = new ClassNode(Short.class),
Integer_TYPE = new ClassNode(Integer.class), Long_TYPE = new ClassNode(Long.class),
Character_TYPE = new ClassNode(Character.class), Float_TYPE = new ClassNode(Float.class),
Double_TYPE = new ClassNode(Double.class), Boolean_TYPE = new ClassNode(Boolean.class),
BigInteger_TYPE = new ClassNode(java.math.BigInteger.class),
BigDecimal_TYPE = new ClassNode(java.math.BigDecimal.class),
void_WRAPPER_TYPE = new ClassNode(Void.class),
CLASS_Type = new ClassNode(Class.class), METACLASS_TYPE = new ClassNode(MetaClass.class),
GENERATED_CLOSURE_Type = new ClassNode(GeneratedClosure.class),
Enum_Type = new ClassNode("java.lang.Enum",0,OBJECT_TYPE);
static {
Enum_Type.isPrimaryNode = false;
}
private static ClassNode[] types = new ClassNode[] {
OBJECT_TYPE,
boolean_TYPE, char_TYPE, byte_TYPE, short_TYPE,
int_TYPE, long_TYPE, double_TYPE, float_TYPE,
VOID_TYPE, CLOSURE_TYPE, GSTRING_TYPE,
LIST_TYPE, MAP_TYPE, RANGE_TYPE, PATTERN_TYPE,
SCRIPT_TYPE, STRING_TYPE, Boolean_TYPE, Character_TYPE,
Byte_TYPE, Short_TYPE, Integer_TYPE, Long_TYPE,
Double_TYPE, Float_TYPE, BigDecimal_TYPE, BigInteger_TYPE,
void_WRAPPER_TYPE, REFERENCE_TYPE, CLASS_Type, METACLASS_TYPE,
GENERATED_CLOSURE_Type, Enum_Type
};
private static ClassNode[] numbers = new ClassNode[] {
char_TYPE, byte_TYPE, short_TYPE, int_TYPE, long_TYPE,
double_TYPE, float_TYPE, Short_TYPE, Byte_TYPE, Character_TYPE,
Integer_TYPE, Float_TYPE, Long_TYPE, Double_TYPE, BigInteger_TYPE,
BigDecimal_TYPE
};
protected static final ClassNode[] EMPTY_TYPE_ARRAY = {};
public static final String OBJECT = "java.lang.Object";
/**
* Creates an array of ClassNodes using an array of classes.
* For each of the given classes a new ClassNode will be
* created
* @see #make(Class)
* @param classes an array of classes used to create the ClassNodes
* @return an array of ClassNodes
*/
public static ClassNode[] make(Class[] classes) {
ClassNode[] cns = new ClassNode[classes.length];
for (int i=0; i<cns.length; i++) {
cns[i] = make(classes[i]);
}
return cns;
}
/**
* Creates a ClassNode using a given class.
* A new ClassNode object is only created if the class
* is not one of the predefined ones
*
* @param c class used to created the ClassNode
* @return ClassNode instance created from the given class
*/
public static ClassNode make(Class c) {
for (int i=0; i<classes.length; i++) {
if (c==classes[i]) return types[i];
}
if (c.isArray()) {
ClassNode cn = make(c.getComponentType());
return cn.makeArray();
}
ClassNode t = new ClassNode(c);
return t;
}
/**
* Creates a ClassNode using a given class.
* Unlike make(String) this method will not use the cache
* to create the ClassNode. This means the ClassNode created
* from this method using the same name will have a different
* references
*
* @see #make(String)
* @param name of the class the ClassNode is representing
*/
public static ClassNode makeWithoutCaching(String name) {
ClassNode cn = new ClassNode(name,Opcodes.ACC_PUBLIC,OBJECT_TYPE);
cn.isPrimaryNode = false;
return cn;
}
/**
* Creates a ClassNode using a given class.
* If the name is one of the predefined ClassNodes then the
* corresponding ClassNode instance will be returned. If the
* is null of of length 0 the dynamic type is returned
*
* @param name of the class the ClassNode is representing
*/
public static ClassNode make(String name) {
if (name == null || name.length() == 0) return DYNAMIC_TYPE;
for (int i=0; i<primitiveClassNames.length; i++) {
if (primitiveClassNames[i].equals(name)) return types[i];
}
for (int i=0; i<classes.length; i++) {
String cname = classes[i].getName();
if (name.equals(cname)) return types[i];
}
return makeWithoutCaching(name);
}
/**
* Creates a ClassNode containing the wrapper of a ClassNode
* of primitive type. Any ClassNode representing a primitive
* type should be created using the predefined types used in
* class. The method will check the parameter for known
* references of ClassNode representing a primitive type. If
* Reference is found, then a ClassNode will be contained that
* represents the wrapper class. For exmaple for boolean, the
* wrapper class is java.lang.Boolean.
*
* If the parameter is no primitve type, the redirected
* ClassNode will be returned
*
* @see #make(Class)
* @see #make(String)
* @param cn the ClassNode containing a possible primitive type
*/
public static ClassNode getWrapper(ClassNode cn) {
cn = cn.redirect();
if (!isPrimitiveType(cn)) return cn;
if (cn==boolean_TYPE) {
return Boolean_TYPE;
} else if (cn==byte_TYPE) {
return Byte_TYPE;
} else if (cn==char_TYPE) {
return Character_TYPE;
} else if (cn==short_TYPE) {
return Short_TYPE;
} else if (cn==int_TYPE) {
return Integer_TYPE;
} else if (cn==long_TYPE) {
return Long_TYPE;
} else if (cn==float_TYPE) {
return Float_TYPE;
} else if (cn==double_TYPE) {
return Double_TYPE;
} else if (cn==VOID_TYPE) {
return void_WRAPPER_TYPE;
}
else {
return cn;
}
}
/**
* Test to determine if a ClasNode is a primitve type.
* Note: this only works for ClassNodes created using a
* predefined ClassNode
*
* @see #make(Class)
* @see #make(String)
* @param cn the ClassNode containing a possible primitive type
* @return true if the ClassNode is a primitve type
*/
public static boolean isPrimitiveType(ClassNode cn) {
return cn == boolean_TYPE ||
cn == char_TYPE ||
cn == byte_TYPE ||
cn == short_TYPE ||
cn == int_TYPE ||
cn == long_TYPE ||
cn == float_TYPE ||
cn == double_TYPE ||
cn == VOID_TYPE;
}
public static ClassNode makeReference() {
return make(Reference.class);
}
public static boolean isUnresolvedEnum(ClassNode node) {
if (Enum_Type.isResolved()) return false;
if (node.isResolved()) return false;
ClassNode superClass = node.getSuperClass();
if (superClass==null) return false;
return superClass.redirect()==Enum_Type;
}
}