001    /*
002     $Id: MethodNode.java 4032 2006-08-30 07:18:49Z mguillem $
003    
004     Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
005    
006     Redistribution and use of this software and associated documentation
007     ("Software"), with or without modification, are permitted provided
008     that the following conditions are met:
009    
010     1. Redistributions of source code must retain copyright
011        statements and notices.  Redistributions must also contain a
012        copy of this document.
013    
014     2. Redistributions in binary form must reproduce the
015        above copyright notice, this list of conditions and the
016        following disclaimer in the documentation and/or other
017        materials provided with the distribution.
018    
019     3. The name "groovy" must not be used to endorse or promote
020        products derived from this Software without prior written
021        permission of The Codehaus.  For written permission,
022        please contact info@codehaus.org.
023    
024     4. Products derived from this Software may not be called "groovy"
025        nor may "groovy" appear in their names without prior written
026        permission of The Codehaus. "groovy" is a registered
027        trademark of The Codehaus.
028    
029     5. Due credit should be given to The Codehaus -
030        http://groovy.codehaus.org/
031    
032     THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
033     ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
034     NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
035     FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
036     THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
037     INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
038     (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
039     SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
040     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
041     STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
042     ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
043     OF THE POSSIBILITY OF SUCH DAMAGE.
044    
045     */
046    package org.codehaus.groovy.ast;
047    
048    import java.util.List;
049    
050    import org.codehaus.groovy.ast.stmt.BlockStatement;
051    import org.codehaus.groovy.ast.stmt.Statement;
052    import org.objectweb.asm.Opcodes;
053    
054    /**
055     * Represents a method declaration
056     *
057     * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
058     * @version $Revision: 4032 $
059     */
060    public class MethodNode extends AnnotatedNode implements Opcodes {
061    
062        private String name;
063        private int modifiers;
064        private ClassNode returnType;
065        private Parameter[] parameters;
066        private boolean hasDefaultValue = false;
067        private Statement code;
068        private boolean dynamicReturnType;
069        private VariableScope variableScope;
070        private ClassNode[] exceptions;
071        
072        public MethodNode(String name, int modifiers, ClassNode returnType, Parameter[] parameters, ClassNode[] exceptions, Statement code) {
073            this.name = name;
074            this.modifiers = modifiers;
075            this.parameters = parameters;
076            this.code = code;
077            this.returnType = returnType;
078            if (returnType==null) this.returnType = ClassHelper.OBJECT_TYPE; 
079    
080            variableScope = new VariableScope();
081            if (parameters != null && parameters.length > 0) {
082                for (int i = 0; i < parameters.length; i++) {
083                    Parameter para = parameters[i];
084                    if (para.hasInitialExpression()) {
085                        this.hasDefaultValue = true;
086                    }
087                    para.setInStaticContext(isStatic());
088                    variableScope.getDeclaredVariables().put(para.getName(),para);
089                }
090            }
091            variableScope.setInStaticContext(isStatic());
092            
093            this.exceptions = exceptions;
094        }
095    
096        /**
097         * The type descriptor for a method node is a string containing the name of the method, its return type,
098         * and its parameter types in a canonical form. For simplicity, I'm using the format of a Java declaration
099         * without parameter names, and with $dynamic as the type for any dynamically typed values.
100         */
101        // TODO: add test case for type descriptor
102        public String getTypeDescriptor() {
103            StringBuffer buf = new StringBuffer();
104            // buf.append(dynamicReturnType ? "$dynamic" : cleanupTypeName(returnType));
105            //
106            buf.append(returnType.getName()); // br  to replace the above. Dynamic type returns Object.
107            //
108            buf.append(' ');
109            buf.append(name);
110            buf.append('(');
111            for (int i = 0; i < parameters.length; i++) {
112                if (i > 0) {
113                    buf.append(',');
114                }
115                Parameter param = parameters[i];
116                buf.append(param.getType().getName());
117            }
118            buf.append(')');
119            return buf.toString();
120        }
121     
122        public boolean isVoidMethod() {
123            return returnType==ClassHelper.VOID_TYPE;
124        }
125    
126        public Statement getCode() {
127            return code;
128        }
129    
130        public void setCode(Statement code) {
131            this.code = code;
132        }
133    
134        public int getModifiers() {
135            return modifiers;
136        }
137    
138        public void setModifiers(int modifiers) {
139            this.modifiers = modifiers;
140        }
141    
142        public String getName() {
143            return name;
144        }
145    
146        public Parameter[] getParameters() {
147            return parameters;
148        }
149    
150        public ClassNode getReturnType() {
151            return returnType;
152        }
153    
154        public VariableScope getVariableScope() {
155            return variableScope;
156        }
157    
158        public void setVariableScope(VariableScope variableScope) {
159            this.variableScope = variableScope;
160        }
161    
162        public boolean isDynamicReturnType() {
163            return dynamicReturnType;
164        }
165    
166        public boolean isAbstract() {
167            return (modifiers & ACC_ABSTRACT) != 0;
168        }
169    
170        public boolean isStatic() {
171            return (modifiers & ACC_STATIC) != 0;
172        }
173    
174        public boolean hasDefaultValue() {
175            return this.hasDefaultValue;
176        }
177    
178        public String toString() {
179            return super.toString() + "[name: " + name + "]";
180        }
181    
182        public void setReturnType(ClassNode returnType) {
183            this.returnType = returnType;
184        }
185    
186        public ClassNode[] getExceptions() {
187            return exceptions;
188        }
189        
190        public Statement getFirstStatement(){
191            if (code == null) return null;
192            if (code instanceof BlockStatement) {
193                List list = ((BlockStatement) code).getStatements();
194                if (list.size()>0) return (Statement) list.get(0);
195                return null;
196            }
197            return code;
198        }
199    }