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 17 package com.android.mkstubs.sourcer; 18 19 import org.objectweb.asm.AnnotationVisitor; 20 import org.objectweb.asm.Attribute; 21 import org.objectweb.asm.ClassVisitor; 22 import org.objectweb.asm.FieldVisitor; 23 import org.objectweb.asm.MethodVisitor; 24 import org.objectweb.asm.Opcodes; 25 import org.objectweb.asm.signature.SignatureReader; 26 27 /** 28 * A class visitor that writes a java source. 29 */ 30 public class ClassSourcer extends ClassVisitor { 31 32 private final Output mOutput; 33 private final AccessSourcer mAccessSourcer; 34 private String mClassName; 35 36 public ClassSourcer(Output output) { 37 super(Opcodes.ASM4); 38 mOutput = output; 39 mAccessSourcer = new AccessSourcer(mOutput); 40 } 41 42 /* Examples: 43 * name = com/foo/MyClass 44 * signature = null (if not generic) 45 * superName = java/lang/Object 46 * interfaces = [ java/lang/Runnable ... ] 47 */ 48 @Override 49 public void visit(int version, int access, String name, String signature, 50 String superName, String[] interfaces) { 51 52 String pkg = name.substring(0, name.lastIndexOf('/')).replace('/', '.'); 53 mClassName = name.substring(name.lastIndexOf('/') + 1); 54 55 mOutput.write("package %s;\n", pkg); 56 57 // dump access keywords. Note: do not dump "super" here 58 mAccessSourcer.write(access & ~Opcodes.ACC_SUPER, AccessSourcer.IS_CLASS); 59 60 // write class name 61 mOutput.write(" class %s", mClassName); 62 63 if (signature != null) { 64 // write template formal definition and super type 65 SignatureReader sigReader = new SignatureReader(signature); 66 SignatureSourcer sigSourcer = new SignatureSourcer(); 67 sigReader.accept(sigSourcer); 68 69 if (sigSourcer.hasFormalsContent()) { 70 mOutput.write(sigSourcer.formalsToString()); 71 } 72 73 mOutput.write(" extends %s", sigSourcer.getSuperClass().toString()); 74 75 } else { 76 // write non-generic super type 77 mOutput.write(" extends %s", superName.replace('/', '.')); 78 } 79 80 // write interfaces defined, if any 81 if (interfaces != null && interfaces.length > 0) { 82 mOutput.write(" implements "); 83 boolean need_sep = false; 84 for (String i : interfaces) { 85 if (need_sep) { 86 mOutput.write(", "); 87 } 88 mOutput.write(i.replace('/', '.')); 89 need_sep = true; 90 } 91 } 92 93 // open class body 94 mOutput.write(" {\n"); 95 } 96 97 @Override 98 public void visitEnd() { 99 mOutput.write("}\n"); 100 } 101 102 @Override 103 public AnnotationVisitor visitAnnotation(String desc, boolean visible) { 104 mOutput.write("@%s", desc); 105 return new AnnotationSourcer(mOutput); 106 } 107 108 @Override 109 public void visitAttribute(Attribute attr) { 110 mOutput.write("%s /* non-standard class attribute */ ", attr.type); 111 } 112 113 114 @Override 115 public FieldVisitor visitField(int access, String name, String desc, String signature, 116 Object value) { 117 // skip synthetic fields 118 if ((access & Opcodes.ACC_SYNTHETIC) != 0) { 119 return null; 120 } 121 122 return new FieldSourcer(mOutput, access, name, desc, signature); 123 } 124 125 @Override 126 public MethodVisitor visitMethod(int access, String name, String desc, String signature, 127 String[] exceptions) { 128 129 // Visit the method and dump its stub. 130 return new MethodSourcer(mOutput, mClassName, access, name, desc, signature, exceptions); 131 } 132 133 @Override 134 public void visitInnerClass(String name, String outerName, String innerName, int access) { 135 // Skip inner classes. This just indicates there's an inner class definition but 136 // they are visited at the top level as separate classes. 137 } 138 139 @Override 140 public void visitOuterClass(String owner, String name, String desc) { 141 // Skip outer classes. 142 } 143 144 @Override 145 public void visitSource(String source, String debug) { 146 // Skip source information. 147 } 148 149 } 150