📄 classnode.java
字号:
/* * $Id: ClassNode.java,v 1.73 2006/06/25 19:58:43 blackdrag Exp $ * * Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved. * * Redistribution and use of this software and associated documentation * ("Software"), with or without modification, are permitted provided that the * following conditions are met: * 1. Redistributions of source code must retain copyright statements and * notices. Redistributions must also contain a copy of this document. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name "groovy" must not be used to endorse or promote products * derived from this Software without prior written permission of The Codehaus. * For written permission, please contact info@codehaus.org. * 4. Products derived from this Software may not be called "groovy" nor may * "groovy" appear in their names without prior written permission of The * Codehaus. "groovy" is a registered trademark of The Codehaus. * 5. Due credit should be given to The Codehaus - http://groovy.codehaus.org/ * * THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS ``AS IS'' AND ANY * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH * DAMAGE. * */package org.codehaus.groovy.ast;import groovy.lang.GroovyObject;import org.codehaus.groovy.GroovyBugError;import org.codehaus.groovy.ast.expr.Expression;import org.codehaus.groovy.ast.expr.TupleExpression;import org.codehaus.groovy.ast.stmt.BlockStatement;import org.codehaus.groovy.ast.stmt.EmptyStatement;import org.codehaus.groovy.ast.stmt.Statement;import org.objectweb.asm.Opcodes;import java.lang.reflect.Array;import java.lang.reflect.Constructor;import java.lang.reflect.Field;import java.lang.reflect.Method;import java.util.ArrayList;import java.util.HashMap;import java.util.HashSet;import java.util.Iterator;import java.util.List;import java.util.Map;/** * Represents a class in the AST.<br/> * A ClassNode should be created using the methods in ClassHelper. * This ClassNode may be used to represent a class declaration or * any other type. This class uses a proxy meschanism allowing to * create a class for a plain name at ast creation time. In another * phase of the compiler the real ClassNode for the plain name may be * found. To avoid the need of exchanging this ClassNode with an * instance of the correct ClassNode the correct ClassNode is set as * redirect. All method calls are then redirected to that ClassNode. * <br> * Note: the proxy mechanism is only allowed for classes being marked * as primary ClassNode which means they represent no actual class. * The redirect itself can be any type of ClassNode * * @see org.codehaus.groovy.ast.ClassHelper * * @author <a href="mailto:james@coredevelopers.net">James Strachan</a> * @author Jochen Theodorou * @version $Revision: 1.73 $ */public class ClassNode extends AnnotatedNode implements Opcodes { public static ClassNode[] EMPTY_ARRAY = new ClassNode[0]; public static ClassNode THIS = new ClassNode(Object.class); public static ClassNode SUPER = new ClassNode(Object.class); private String name; private int modifiers; private ClassNode[] interfaces; private MixinNode[] mixins; private List constructors = new ArrayList(); private List objectInitializers = new ArrayList(); private List methods = new ArrayList(); private List fields = new ArrayList(); private List properties = new ArrayList(); private Map fieldIndex = new HashMap(); private ModuleNode module; private CompileUnit compileUnit; private boolean staticClass = false; private boolean scriptBody = false; private boolean script; private ClassNode superClass; boolean isPrimaryNode; // use this to synchronize access for the lazy intit protected Object lazyInitLock = new Object(); // clazz!=null when resolved protected Class clazz; // only false when this classNode is constructed from a class private boolean lazyInitDone=true; // not null if if the ClassNode is an array private ClassNode componentType = null; // if not null this instance is handled as proxy // for the redirect private ClassNode redirect=null; /** * Returns the ClassNode this ClassNode is redirecting to. */ protected ClassNode redirect(){ if (redirect==null) return this; return redirect.redirect(); } /** * Sets this instance as proxy for the given ClassNode. * @param cn the class to redirect to. If set to null the redirect will be removed */ public void setRedirect(ClassNode cn) { if (isPrimaryNode) throw new GroovyBugError("tried to set a redirect for a primary ClassNode ("+getName()+"->"+cn.getName()+")."); if (cn!=null) cn = cn.redirect(); redirect = cn; } /** * Returns a ClassNode representing an array of the class * represented by this ClassNode */ public ClassNode makeArray() { if (redirect!=null) return redirect().makeArray(); ClassNode cn; if (clazz!=null) { Class ret = Array.newInstance(clazz,0).getClass(); // don't use the ClassHelper here! cn = new ClassNode(ret,this); } else { cn = new ClassNode(this); } return cn; } /** * Returns if this instance is a primary ClassNode */ public boolean isPrimaryClassNode(){ return redirect().isPrimaryNode || (componentType!= null && componentType.isPrimaryClassNode()); } /** * Constructor used by makeArray() if no real class is available */ private ClassNode(ClassNode componentType) { this(componentType.getName()+"[]", ACC_PUBLIC, ClassHelper.OBJECT_TYPE); this.componentType = componentType.redirect(); isPrimaryNode=false; } /** * Constructor used by makeArray() if a real class is available */ private ClassNode(Class c, ClassNode componentType) { this(c); this.componentType = componentType; isPrimaryNode=false; } /** * Creates a ClassNode from a real class. The resulting * ClassNode will be no primary ClassNode. */ public ClassNode(Class c) { this(c.getName(), c.getModifiers(), null, null ,MixinNode.EMPTY_ARRAY); clazz=c; lazyInitDone=false; CompileUnit cu = getCompileUnit(); if (cu!=null) cu.addClass(this); isPrimaryNode=false; } /** * The complete class structure will be initialized only when really * needed to avoid having too much objects during compilation */ private void lazyClassInit() { synchronized (lazyInitLock) { if (lazyInitDone) return; Field[] fields = clazz.getDeclaredFields(); for (int i=0;i<fields.length;i++){ addField(fields[i].getName(),fields[i].getModifiers(),this,null); } Method[] methods = clazz.getDeclaredMethods(); for (int i=0;i<methods.length;i++){ Method m = methods[i]; MethodNode mn = new MethodNode(m.getName(), m.getModifiers(), ClassHelper.make(m.getReturnType()), createParameters(m.getParameterTypes()), ClassHelper.make(m.getExceptionTypes()), null); addMethod(mn); } Constructor[] constructors = clazz.getConstructors(); for (int i=0;i<constructors.length;i++){ Constructor ctor = constructors[i]; addConstructor(ctor.getModifiers(),createParameters(ctor.getParameterTypes()),ClassHelper.make(ctor.getExceptionTypes()),null); } Class sc = clazz.getSuperclass(); if (sc!=null) superClass = ClassHelper.make(sc); buildInterfaceTypes(clazz); lazyInitDone=true; } } private void buildInterfaceTypes(Class c) { Class[] interfaces = c.getInterfaces(); ClassNode[] ret = new ClassNode[interfaces.length]; for (int i=0;i<interfaces.length;i++){ ret[i] = ClassHelper.make(interfaces[i]); } this.interfaces = ret; } // added to track the enclosing method for local inner classes private MethodNode enclosingMethod = null; public MethodNode getEnclosingMethod() { return redirect().enclosingMethod; } public void setEnclosingMethod(MethodNode enclosingMethod) { redirect().enclosingMethod = enclosingMethod; } /** * @param name is the full name of the class * @param modifiers the modifiers, * @param superClass the base class name - use "java.lang.Object" if no direct * base class * @see org.objectweb.asm.Opcodes */ public ClassNode(String name, int modifiers, ClassNode superClass) { this(name, modifiers, superClass, ClassHelper.EMPTY_TYPE_ARRAY, MixinNode.EMPTY_ARRAY); } /** * @param name is the full name of the class * @param modifiers the modifiers, * @param superClass the base class name - use "java.lang.Object" if no direct * base class * @see org.objectweb.asm.Opcodes */ public ClassNode(String name, int modifiers, ClassNode superClass, ClassNode[] interfaces, MixinNode[] mixins) { this.name = name; this.modifiers = modifiers; this.superClass = superClass; this.interfaces = interfaces; this.mixins = mixins; isPrimaryNode = true; } /** * Sets the superclass of this ClassNode */ public void setSuperClass(ClassNode superClass) { redirect().superClass = superClass; } /** * Returns a list containing FieldNode objects for * each field in the class represented by this ClassNode */ public List getFields() { if (!lazyInitDone) { lazyClassInit(); } if (redirect!=null) return redirect().getFields(); return fields; } /** * Returns an array of ClassNodes representing the * interfaces the class implements */ public ClassNode[] getInterfaces() { if (!lazyInitDone) { lazyClassInit(); } if (redirect!=null) return redirect().getInterfaces(); return interfaces; } public MixinNode[] getMixins() { return redirect().mixins; } /** * Returns a list containing MethodNode objects for * each method in the class represented by this ClassNode */ public List getMethods() { if (!lazyInitDone) { lazyClassInit(); } if (redirect!=null) return redirect().getMethods(); return methods; } /** * Returns a list containing MethodNode objects for * each abstract method in the class represented by * this ClassNode */ public List getAbstractMethods() { HashSet abstractNodes = new HashSet();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -