View Javadoc

1   /*
2    $Id: MethodNode.java,v 1.16 2005/05/27 10:13:08 russel Exp $
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 org.codehaus.groovy.ast.stmt.Statement;
49  import org.codehaus.groovy.classgen.VariableScopeCodeVisitor;
50  import org.objectweb.asm.Opcodes;
51  
52  /***
53   * Represents a method declaration
54   *
55   * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
56   * @version $Revision: 1.16 $
57   */
58  public class MethodNode extends AnnotatedNode implements Opcodes {
59  
60      private String name;
61      private int modifiers;
62      private String returnType;
63      private Parameter[] parameters;
64      private Statement code;
65      private boolean dynamicReturnType;
66      private VariableScope variableScope;
67  
68      public MethodNode(String name, int modifiers, String returnType, Parameter[] parameters, Statement code) {
69          this.name = name;
70          this.modifiers = modifiers;
71          this.parameters = parameters;
72          this.code = code;
73  
74          if (returnType == null || returnType.length() == 0) {
75              this.returnType = "java.lang.Object";
76              this.dynamicReturnType = true;
77          }
78          else {
79              this.returnType = ensureJavaTypeNameSyntax(returnType);
80          }
81      }
82  
83      /***
84       * The type descriptor for a method node is a string containing the name of the method, its return type,
85       * and its parameter types in a canonical form. For simplicity, I'm using the format of a Java declaration
86       * without parameter names, and with $dynamic as the type for any dynamically typed values.
87       *
88       * @return
89       */
90      // TODO: add test case for type descriptor
91      public String getTypeDescriptor() {
92          StringBuffer buf = new StringBuffer();
93          // buf.append(dynamicReturnType ? "$dynamic" : cleanupTypeName(returnType));
94          //
95          buf.append(ensureJavaTypeNameSyntax(returnType)); // br  to replace the above. Dynamic type returns Object.
96          //
97          buf.append(' ');
98          buf.append(name);
99          buf.append('(');
100         for (int i = 0; i < parameters.length; i++) {
101             if (i > 0) {
102                 buf.append(',');
103             }
104             Parameter param = parameters[i];
105             buf.append(ensureJavaTypeNameSyntax(param.getType()));
106         }
107         buf.append(')');
108         return buf.toString();
109     }
110 
111     public static String ensureJavaTypeNameSyntax(String typename) {
112         // if the typename begins with "[", ends with ";", or is
113         // one character long, it's in .class syntax.
114         if (typename.charAt(0) == '[') {
115             return ensureJavaTypeNameSyntax(typename.substring(1)) + "[]";
116         }
117         if (typename.length() == 1) {
118             switch (typename.charAt(0)) {
119                 case 'B':
120                     return "byte";
121                 case 'C':
122                     return "char";
123                 case 'D':
124                     return "double";
125                 case 'F':
126                     return "float";
127                 case 'J':
128                     return "long";
129                 case 'I':
130                     return "int";
131                 case 'S':
132                     return "short";
133                 case 'V':
134                     return "void";
135                 case 'Z':
136                     return "boolean";
137             }
138         }
139         if (typename.endsWith(";")) {
140             // Type should be "Lclassname;"
141             return typename.substring(1, typename.length() - 1);
142         }
143         return typename;
144 
145     }
146 
147     public boolean isVoidMethod() {
148         return "void".equals(returnType);
149     }
150 
151     public Statement getCode() {
152         return code;
153     }
154 
155     public void setCode(Statement code) {
156         this.code = code;
157     }
158 
159     public int getModifiers() {
160         return modifiers;
161     }
162 
163     public void setModifiers(int modifiers) {
164         this.modifiers = modifiers;
165     }
166 
167     public String getName() {
168         return name;
169     }
170 
171     public Parameter[] getParameters() {
172         return parameters;
173     }
174 
175     public String getReturnType() {
176         return returnType;
177     }
178 
179     public VariableScope getVariableScope() {
180         if (variableScope == null) {
181             variableScope = createVariableScope();
182         }
183         return variableScope;
184     }
185 
186     public void setVariableScope(VariableScope variableScope) {
187         this.variableScope = variableScope;
188     }
189 
190     public boolean isDynamicReturnType() {
191         return dynamicReturnType;
192     }
193 
194     public boolean isAbstract() {
195         return (modifiers & ACC_ABSTRACT) != 0;
196     }
197 
198     public boolean isStatic() {
199         return (modifiers & ACC_STATIC) != 0;
200     }
201 
202     public String toString() {
203         return super.toString() + "[name: " + name + "]";
204     }
205 
206     public void setReturnType(String returnType) {
207         this.returnType = returnType;
208     }
209 
210 
211     protected VariableScope createVariableScope() {
212         VariableScope variableScope = new VariableScope();
213         VariableScopeCodeVisitor visitor = new VariableScopeCodeVisitor(variableScope);
214         visitor.setParameters(getParameters());
215         Statement code = getCode();
216         if (code != null) {
217             code.visit(visitor);
218         }
219         addFieldsToVisitor(variableScope);
220         return variableScope;
221     }
222 }