1/*
2 * Copyright (C) 2009 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.mkstubs.sourcer;
18
19import org.objectweb.asm.AnnotationVisitor;
20import org.objectweb.asm.Attribute;
21import org.objectweb.asm.Label;
22import org.objectweb.asm.MethodVisitor;
23import org.objectweb.asm.Opcodes;
24import org.objectweb.asm.Type;
25import org.objectweb.asm.signature.SignatureReader;
26
27import java.util.ArrayList;
28
29/**
30 * A method visitor that generates the Java source for a whole method.
31 */
32class MethodSourcer extends MethodVisitor {
33
34    private final Output mOutput;
35    private final int mAccess;
36    private final String mClassName;
37    private final String mName;
38    private final String mDesc;
39    private final String mSignature;
40    private final String[] mExceptions;
41    private boolean mNeedDeclaration;
42    private boolean mIsConstructor;
43
44    public MethodSourcer(Output output, String className, int access, String name,
45            String desc, String signature, String[] exceptions) {
46        super(Opcodes.ASM4);
47        mOutput = output;
48        mClassName = className;
49        mAccess = access;
50        mName = name;
51        mDesc = desc;
52        mSignature = signature;
53        mExceptions = exceptions;
54
55        mNeedDeclaration = true;
56        mIsConstructor = "<init>".equals(name);
57    }
58
59    private void writeHeader() {
60        if (!mNeedDeclaration) {
61            return;
62        }
63
64        AccessSourcer as = new AccessSourcer(mOutput);
65        as.write(mAccess, AccessSourcer.IS_METHOD);
66
67        // preprocess the signature to get the return type and the arguments
68        SignatureSourcer sigSourcer = null;
69        if (mSignature != null) {
70            SignatureReader sigReader = new SignatureReader(mSignature);
71            sigSourcer = new SignatureSourcer();
72            sigReader.accept(sigSourcer);
73
74            if (sigSourcer.hasFormalsContent()) {
75                // dump formal template parameter definitions
76                mOutput.write(" %s", sigSourcer.formalsToString());
77            }
78        }
79
80        // output return type (constructor have no return type)
81        if (!mIsConstructor) {
82            // The signature overrides desc, if present
83            if (sigSourcer == null || sigSourcer.getReturnType() == null) {
84                mOutput.write(" %s", Type.getReturnType(mDesc).getClassName());
85
86            } else {
87                mOutput.write(" %s", sigSourcer.getReturnType().toString());
88            }
89        }
90
91        // output name
92        mOutput.write(" %s(", mIsConstructor ? mClassName : mName);
93
94        // output arguments. The signature overrides desc, if present
95        if (mSignature == null) {
96            Type[] types = Type.getArgumentTypes(mDesc);
97
98            for(int i = 0; i < types.length; i++) {
99                if (i > 0) {
100                    mOutput.write(", ");
101                }
102                mOutput.write("%s arg%d", types[i].getClassName(), i);
103            }
104        } else {
105            ArrayList<SignatureSourcer> params = sigSourcer.getParameters();
106
107            for(int i = 0; i < params.size(); i++) {
108                if (i > 0) {
109                    mOutput.write(", ");
110                }
111                mOutput.write("%s arg%d", params.get(i).toString(), i);
112            }
113        }
114        mOutput.write(")");
115
116        // output throwable exceptions
117        if (mExceptions != null && mExceptions.length > 0) {
118            mOutput.write(" throws ");
119
120            for (int i = 0; i < mExceptions.length; i++) {
121                if (i > 0) {
122                    mOutput.write(", ");
123                }
124                mOutput.write(mExceptions[i].replace('/', '.'));
125            }
126        }
127
128        mOutput.write(" {\n");
129
130        mNeedDeclaration = false;
131    }
132
133    @Override
134    public void visitCode() {
135        writeHeader();
136
137        // write the stub itself
138        mOutput.write("throw new RuntimeException(\"Stub\");");
139    }
140
141    @Override
142    public void visitEnd() {
143        writeHeader();
144        mOutput.write("\n}\n");
145    }
146
147    @Override
148    public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
149        mOutput.write("@%s", desc);
150        return new AnnotationSourcer(mOutput);
151    }
152
153    @Override
154    public AnnotationVisitor visitAnnotationDefault() {
155        // pass
156        return null;
157    }
158
159    @Override
160    public void visitAttribute(Attribute attr) {
161        mOutput.write("%s /* non-standard method attribute */ ", attr.type);
162    }
163
164    @Override
165    public void visitFieldInsn(int opcode, String owner, String name, String desc) {
166        // pass
167    }
168
169    @Override
170    public void visitFrame(int type, int local, Object[] local2, int stack, Object[] stack2) {
171        // pass
172    }
173
174    @Override
175    public void visitIincInsn(int var, int increment) {
176        // pass
177    }
178
179    @Override
180    public void visitInsn(int opcode) {
181        // pass
182    }
183
184    @Override
185    public void visitIntInsn(int opcode, int operand) {
186        // pass
187    }
188
189    @Override
190    public void visitJumpInsn(int opcode, Label label) {
191        // pass
192    }
193
194    @Override
195    public void visitLabel(Label label) {
196        // pass
197    }
198
199    @Override
200    public void visitLdcInsn(Object cst) {
201        // pass
202    }
203
204    @Override
205    public void visitLineNumber(int line, Label start) {
206        // pass
207    }
208
209    @Override
210    public void visitLocalVariable(String name, String desc, String signature,
211            Label start, Label end, int index) {
212        // pass
213    }
214
215    @Override
216    public void visitLookupSwitchInsn(Label dflt, int[] keys, Label[] labels) {
217        // pass
218    }
219
220    @Override
221    public void visitMaxs(int maxStack, int maxLocals) {
222        // pass
223    }
224
225    @Override
226    public void visitMethodInsn(int opcode, String owner, String name, String desc) {
227        // pass
228    }
229
230    @Override
231    public void visitMultiANewArrayInsn(String desc, int dims) {
232        // pass
233    }
234
235    @Override
236    public AnnotationVisitor visitParameterAnnotation(int parameter, String desc, boolean visible) {
237        // pass
238        return null;
239    }
240
241    @Override
242    public void visitTableSwitchInsn(int min, int max, Label dflt, Label[] labels) {
243        // pass
244    }
245
246    @Override
247    public void visitTryCatchBlock(Label start, Label end, Label handler, String type) {
248        // pass
249    }
250
251    @Override
252    public void visitTypeInsn(int opcode, String type) {
253        // pass
254    }
255
256    @Override
257    public void visitVarInsn(int opcode, int var) {
258        // pass
259    }
260
261}
262