/Users/lyon/j4p/src/javassist/expr/MethodCall.java

1    /* 
2     * Javassist, a Java-bytecode translator toolkit. 
3     * Copyright (C) 1999-2003 Shigeru Chiba. All Rights Reserved. 
4     * 
5     * The contents of this file are subject to the Mozilla Public License Version 
6     * 1.1 (the "License"); you may not use this file except in compliance with 
7     * the License.  Alternatively, the contents of this file may be used under 
8     * the terms of the GNU Lesser General Public License Version 2.1 or later. 
9     * 
10    * Software distributed under the License is distributed on an "AS IS" basis, 
11    * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License 
12    * for the specific language governing rights and limitations under the 
13    * License. 
14    */ 
15    
16   package javassist.expr; 
17    
18   import javassist.*; 
19   import javassist.bytecode.*; 
20   import javassist.compiler.*; 
21    
22   /** 
23    * Method invocation (caller-side expression). 
24    */ 
25   public class MethodCall extends Expr { 
26       /** 
27        * Undocumented constructor.  Do not use; internal-use only. 
28        */ 
29       MethodCall(int pos, CodeIterator i, CtClass declaring, MethodInfo m) { 
30           super(pos, i, declaring, m); 
31       } 
32    
33       private int getNameAndType(ConstPool cp) { 
34           String cname; 
35           int pos = currentPos; 
36           int c = iterator.byteAt(pos); 
37           int index = iterator.u16bitAt(pos + 1); 
38    
39           if (c == INVOKEINTERFACE) 
40               return cp.getInterfaceMethodrefNameAndType(index); 
41           else 
42               return cp.getMethodrefNameAndType(index); 
43       } 
44    
45       /** 
46        * Returns the method or constructor containing the method-call 
47        * expression represented by this object. 
48        */ 
49       public CtBehavior where() { 
50           return super.where(); 
51       } 
52    
53       /** 
54        * Returns the line number of the source line containing the 
55        * method call. 
56        * 
57        * @return -1       if this information is not available. 
58        */ 
59       public int getLineNumber() { 
60           return super.getLineNumber(); 
61       } 
62    
63       /** 
64        * Returns the source file containing the method call. 
65        * 
66        * @return null     if this information is not available. 
67        */ 
68       public String getFileName() { 
69           return super.getFileName(); 
70       } 
71    
72       /** 
73        * Returns the class of the target object, 
74        * which the method is called on. 
75        */ 
76       private CtClass getCtClass() throws NotFoundException { 
77           return thisClass.getClassPool().get(getClassName()); 
78       } 
79    
80       /** 
81        * Returns the class name of the target object, 
82        * which the method is called on. 
83        */ 
84       public String getClassName() { 
85           String cname; 
86    
87           ConstPool cp = getConstPool(); 
88           int pos = currentPos; 
89           int c = iterator.byteAt(pos); 
90           int index = iterator.u16bitAt(pos + 1); 
91    
92           if (c == INVOKEINTERFACE) 
93               cname = cp.getInterfaceMethodrefClassName(index); 
94           else 
95               cname = cp.getMethodrefClassName(index); 
96    
97           return cname; 
98       } 
99    
100      /** 
101       * Returns the name of the called method. 
102       */ 
103      public String getMethodName() { 
104          ConstPool cp = getConstPool(); 
105          int nt = getNameAndType(cp); 
106          return cp.getUtf8Info(cp.getNameAndTypeName(nt)); 
107      } 
108   
109      /** 
110       * Returns the called method. 
111       */ 
112      public CtMethod getMethod() throws NotFoundException { 
113          return getCtClass().getMethod(getMethodName(), getMethodDesc()); 
114      } 
115   
116      private String getMethodDesc() { 
117          ConstPool cp = getConstPool(); 
118          int nt = getNameAndType(cp); 
119          return cp.getUtf8Info(cp.getNameAndTypeDescriptor(nt)); 
120      } 
121   
122      /** 
123       * Returns the list of exceptions that the expression may throw. 
124       * This list includes both the exceptions that the try-catch statements 
125       * including the expression can catch and the exceptions that 
126       * the throws declaration allows the method to throw. 
127       */ 
128      public CtClass[] mayThrow() { 
129          return super.mayThrow(); 
130      } 
131   
132      /** 
133       * Returns true if the called method is of a superclass of the current 
134       * class. 
135       */ 
136      public boolean isSuper() { 
137          return iterator.byteAt(currentPos) == INVOKESPECIAL 
138                  && !where().getDeclaringClass().getName().equals(getClassName()); 
139      } 
140   
141      /* 
142       * Returns the parameter types of the called method. 
143   
144      public CtClass[] getParameterTypes() throws NotFoundException { 
145          return Descriptor.getParameterTypes(getMethodDesc(), 
146                                              thisClass.getClassPool()); 
147      } 
148      */ 
149   
150      /* 
151       * Returns the return type of the called method. 
152   
153      public CtClass getReturnType() throws NotFoundException { 
154          return Descriptor.getReturnType(getMethodDesc(), 
155                                          thisClass.getClassPool()); 
156      } 
157      */ 
158   
159      /** 
160       * Replaces the method call with the bytecode derived from 
161       * the given source text. 
162       * 
163       * <p>$0 is available even if the called method is static. 
164       * 
165       * @param statement         a Java statement. 
166       */ 
167      public void replace(String statement) throws CannotCompileException { 
168          ConstPool constPool = getConstPool(); 
169          int pos = currentPos; 
170          int index = iterator.u16bitAt(pos + 1); 
171   
172          String classname, methodname, signature; 
173          int opcodeSize; 
174          int c = iterator.byteAt(pos); 
175          if (c == INVOKEINTERFACE) { 
176              opcodeSize = 5; 
177              classname = constPool.getInterfaceMethodrefClassName(index); 
178              methodname = constPool.getInterfaceMethodrefName(index); 
179              signature = constPool.getInterfaceMethodrefType(index); 
180          } else if (c == INVOKESTATIC 
181                  || c == INVOKESPECIAL || c == INVOKEVIRTUAL) { 
182              opcodeSize = 3; 
183              classname = constPool.getMethodrefClassName(index); 
184              methodname = constPool.getMethodrefName(index); 
185              signature = constPool.getMethodrefType(index); 
186          } else 
187              throw new CannotCompileException("not method invocation"); 
188   
189          Javac jc = new Javac(thisClass); 
190          ClassPool cp = thisClass.getClassPool(); 
191          CodeAttribute ca = iterator.get(); 
192          try { 
193              CtClass[] params = Descriptor.getParameterTypes(signature, cp); 
194              CtClass retType = Descriptor.getReturnType(signature, cp); 
195              int paramVar = ca.getMaxLocals(); 
196              jc.recordParams(classname, params, 
197                      true, paramVar, withinStatic()); 
198              int retVar = jc.recordReturnType(retType, true); 
199              jc.recordProceed(Javac.param0Name, methodname); 
200   
201              /* Is $_ included in the source code? 
202               */ 
203              checkResultValue(retType, statement); 
204   
205              Bytecode bytecode = jc.getBytecode(); 
206              storeStack(params, c == INVOKESTATIC, paramVar, bytecode); 
207              jc.compileStmnt(statement); 
208              if (retType != CtClass.voidType) 
209                  bytecode.addLoad(retVar, retType); 
210   
211              replace0(pos, bytecode, opcodeSize); 
212          } catch (CompileError e) { 
213              throw new CannotCompileException(e); 
214          } catch (NotFoundException e) { 
215              throw new CannotCompileException(e); 
216          } catch (BadBytecode e) { 
217              throw new CannotCompileException("broken method"); 
218          } 
219      } 
220  } 
221