/* * Copyright (C) 2009 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.mkstubs.sourcer; import org.objectweb.asm.AnnotationVisitor; import org.objectweb.asm.Attribute; import org.objectweb.asm.Label; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Type; import org.objectweb.asm.signature.SignatureReader; import java.util.ArrayList; /** * A method visitor that generates the Java source for a whole method. */ class MethodSourcer implements MethodVisitor { private final Output mOutput; private final int mAccess; private final String mClassName; private final String mName; private final String mDesc; private final String mSignature; private final String[] mExceptions; private boolean mNeedDeclaration; private boolean mIsConstructor; public MethodSourcer(Output output, String className, int access, String name, String desc, String signature, String[] exceptions) { mOutput = output; mClassName = className; mAccess = access; mName = name; mDesc = desc; mSignature = signature; mExceptions = exceptions; mNeedDeclaration = true; mIsConstructor = "<init>".equals(name); } private void writeHeader() { if (!mNeedDeclaration) { return; } AccessSourcer as = new AccessSourcer(mOutput); as.write(mAccess, AccessSourcer.IS_METHOD); // preprocess the signature to get the return type and the arguments SignatureSourcer sigSourcer = null; if (mSignature != null) { SignatureReader sigReader = new SignatureReader(mSignature); sigSourcer = new SignatureSourcer(); sigReader.accept(sigSourcer); if (sigSourcer.hasFormalsContent()) { // dump formal template parameter definitions mOutput.write(" %s", sigSourcer.formalsToString()); } } // output return type (constructor have no return type) if (!mIsConstructor) { // The signature overrides desc, if present if (sigSourcer == null || sigSourcer.getReturnType() == null) { mOutput.write(" %s", Type.getReturnType(mDesc).getClassName()); } else { mOutput.write(" %s", sigSourcer.getReturnType().toString()); } } // output name mOutput.write(" %s(", mIsConstructor ? mClassName : mName); // output arguments. The signature overrides desc, if present if (mSignature == null) { Type[] types = Type.getArgumentTypes(mDesc); for(int i = 0; i < types.length; i++) { if (i > 0) { mOutput.write(", "); } mOutput.write("%s arg%d", types[i].getClassName(), i); } } else { ArrayList<SignatureSourcer> params = sigSourcer.getParameters(); for(int i = 0; i < params.size(); i++) { if (i > 0) { mOutput.write(", "); } mOutput.write("%s arg%d", params.get(i).toString(), i); } } mOutput.write(")"); // output throwable exceptions if (mExceptions != null && mExceptions.length > 0) { mOutput.write(" throws "); for (int i = 0; i < mExceptions.length; i++) { if (i > 0) { mOutput.write(", "); } mOutput.write(mExceptions[i].replace('/', '.')); } } mOutput.write(" {\n"); mNeedDeclaration = false; } public void visitCode() { writeHeader(); // write the stub itself mOutput.write("throw new RuntimeException(\"Stub\");"); } public void visitEnd() { writeHeader(); mOutput.write("\n}\n"); } public AnnotationVisitor visitAnnotation(String desc, boolean visible) { mOutput.write("@%s", desc); return new AnnotationSourcer(mOutput); } public AnnotationVisitor visitAnnotationDefault() { // pass return null; } public void visitAttribute(Attribute attr) { mOutput.write("%s /* non-standard method attribute */ ", attr.type); } public void visitFieldInsn(int opcode, String owner, String name, String desc) { // pass } public void visitFrame(int type, int local, Object[] local2, int stack, Object[] stack2) { // pass } public void visitIincInsn(int var, int increment) { // pass } public void visitInsn(int opcode) { // pass } public void visitIntInsn(int opcode, int operand) { // pass } public void visitJumpInsn(int opcode, Label label) { // pass } public void visitLabel(Label label) { // pass } public void visitLdcInsn(Object cst) { // pass } public void visitLineNumber(int line, Label start) { // pass } public void visitLocalVariable(String name, String desc, String signature, Label start, Label end, int index) { // pass } public void visitLookupSwitchInsn(Label dflt, int[] keys, Label[] labels) { // pass } public void visitMaxs(int maxStack, int maxLocals) { // pass } public void visitMethodInsn(int opcode, String owner, String name, String desc) { // pass } public void visitMultiANewArrayInsn(String desc, int dims) { // pass } public AnnotationVisitor visitParameterAnnotation(int parameter, String desc, boolean visible) { // pass return null; } public void visitTableSwitchInsn(int min, int max, Label dflt, Label[] labels) { // pass } public void visitTryCatchBlock(Label start, Label end, Label handler, String type) { // pass } public void visitTypeInsn(int opcode, String type) { // pass } public void visitVarInsn(int opcode, int var) { // pass } }