View Javadoc

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