AI 145983: am: CL 145911 ADT #1778786: tool to generate stubbed jar file.
This is only a preliminary CL. More will follow but this is a good start, with the following caveats: What it does: - take an input jar, a list of includes, a list of excludes. - generate actual Java source for the filtered classes. What it doesn't do yet: - some more work on filtering inner elements (methods, etc.) - properly generate inner classes. - hide synthetic fields. - some classes body are missing - directly generate a stubbed bytecode/jar rather than source. I'll likely want to keep the source generator for debugging purposes or if we want to integrate with a build system instead. - classpath will be changed in the final CL to refer to the external ASM lib rather than the project. I need the source for debugging rigth now. - will review comments before submitting. Original author: raphael Merged from: //branches/cupcake/... Automated import of CL 145983
This commit is contained in:
committed by
The Android Open Source Project
parent
ca7264c7b7
commit
1297169e09
9
tools/mkstubs/.classpath
Normal file
9
tools/mkstubs/.classpath
Normal file
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<classpath>
|
||||
<classpathentry kind="src" path="src"/>
|
||||
<classpathentry kind="src" path="tests"/>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/J2SE-1.5"/>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.junit.JUNIT_CONTAINER/4"/>
|
||||
<classpathentry combineaccessrules="false" kind="src" path="/asm3"/>
|
||||
<classpathentry kind="output" path="bin"/>
|
||||
</classpath>
|
||||
18
tools/mkstubs/.project
Normal file
18
tools/mkstubs/.project
Normal file
@@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>MkStubs</name>
|
||||
<comment></comment>
|
||||
<projects>
|
||||
<project>asm3</project>
|
||||
</projects>
|
||||
<buildSpec>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.jdt.core.javabuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
</buildSpec>
|
||||
<natures>
|
||||
<nature>org.eclipse.jdt.core.javanature</nature>
|
||||
</natures>
|
||||
</projectDescription>
|
||||
28
tools/mkstubs/Android.mk
Normal file
28
tools/mkstubs/Android.mk
Normal file
@@ -0,0 +1,28 @@
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
LOCAL_PATH := $(call my-dir)
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_SRC_FILES := $(call all-java-files-under,src)
|
||||
|
||||
LOCAL_JAR_MANIFEST := manifest.txt
|
||||
LOCAL_STATIC_JAVA_LIBRARIES := \
|
||||
asm-3.1
|
||||
|
||||
LOCAL_MODULE := mkstubs
|
||||
|
||||
include $(BUILD_HOST_JAVA_LIBRARY)
|
||||
|
||||
1
tools/mkstubs/manifest.txt
Normal file
1
tools/mkstubs/manifest.txt
Normal file
@@ -0,0 +1 @@
|
||||
Main-Class: com.android.mkstubs.Main
|
||||
137
tools/mkstubs/src/com/android/mkstubs/AsmAnalyzer.java
Normal file
137
tools/mkstubs/src/com/android/mkstubs/AsmAnalyzer.java
Normal file
@@ -0,0 +1,137 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import org.objectweb.asm.ClassReader;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.TreeMap;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipFile;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
class AsmAnalyzer {
|
||||
|
||||
/**
|
||||
* Parses a JAR file and returns a list of all classes founds using a map
|
||||
* class name => ASM ClassReader. Class names are in the form "android.view.View".
|
||||
*/
|
||||
Map<String,ClassReader> parseInputJar(String inputJarPath) throws IOException {
|
||||
TreeMap<String, ClassReader> classes = new TreeMap<String, ClassReader>();
|
||||
|
||||
ZipFile zip = new ZipFile(inputJarPath);
|
||||
Enumeration<? extends ZipEntry> entries = zip.entries();
|
||||
ZipEntry entry;
|
||||
while (entries.hasMoreElements()) {
|
||||
entry = entries.nextElement();
|
||||
if (entry.getName().endsWith(".class")) {
|
||||
ClassReader cr = new ClassReader(zip.getInputStream(entry));
|
||||
String className = classReaderToAsmName(cr);
|
||||
classes.put(className, cr);
|
||||
}
|
||||
}
|
||||
|
||||
return classes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility that returns the fully qualified ASM class name for a ClassReader.
|
||||
* E.g. it returns something like android/view/View.
|
||||
*/
|
||||
static String classReaderToAsmName(ClassReader classReader) {
|
||||
if (classReader == null) {
|
||||
return null;
|
||||
} else {
|
||||
return classReader.getClassName();
|
||||
}
|
||||
}
|
||||
|
||||
public void filter(
|
||||
Map<String, ClassReader> classes,
|
||||
ArrayList<String> inclusions,
|
||||
ArrayList<String> exclusions) {
|
||||
|
||||
ArrayList<String> inPrefix = new ArrayList<String>();
|
||||
HashSet <String> inFull = new HashSet <String>();
|
||||
ArrayList<String> exPrefix = new ArrayList<String>();
|
||||
HashSet <String> exFull = new HashSet <String>();
|
||||
|
||||
for (String in : inclusions) {
|
||||
if (in.endsWith("*")) {
|
||||
inPrefix.add(in.substring(0, in.length() - 1));
|
||||
} else {
|
||||
inFull.add(in);
|
||||
}
|
||||
}
|
||||
|
||||
for (String ex : exclusions) {
|
||||
if (ex.endsWith("*")) {
|
||||
exPrefix.add(ex.substring(0, ex.length() - 1));
|
||||
} else {
|
||||
exFull.add(ex);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Set<String> keys = classes.keySet();
|
||||
for(Iterator<String> it = keys.iterator(); it.hasNext(); ) {
|
||||
String key = it.next();
|
||||
|
||||
|
||||
// Check if it can be included.
|
||||
boolean keep = inFull.contains(key);
|
||||
if (!keep) {
|
||||
// Check for a prefix inclusion
|
||||
for (String prefix : inPrefix) {
|
||||
if (key.startsWith(prefix)) {
|
||||
keep = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (keep) {
|
||||
// check for a full exclusion
|
||||
keep = !exFull.contains(key);
|
||||
}
|
||||
if (keep) {
|
||||
// or check for prefix exclusion
|
||||
for (String prefix : exPrefix) {
|
||||
if (key.startsWith(prefix)) {
|
||||
keep = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// remove if we don't keep it
|
||||
if (!keep) {
|
||||
System.out.println("- Remove class " + key);
|
||||
it.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
90
tools/mkstubs/src/com/android/mkstubs/AsmGenerator.java
Normal file
90
tools/mkstubs/src/com/android/mkstubs/AsmGenerator.java
Normal file
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import com.android.mkstubs.sourcer.JavaSourcer;
|
||||
import com.android.mkstubs.sourcer.Output;
|
||||
|
||||
import org.objectweb.asm.ClassReader;
|
||||
import org.objectweb.asm.ClassVisitor;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.io.Writer;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
class AsmGenerator {
|
||||
|
||||
/**
|
||||
* Generate source for the stubbed classes, mostly for debug purposes.
|
||||
* @throws IOException
|
||||
*/
|
||||
public void generateSource(File baseDir,
|
||||
Map<String, ClassReader> classes,
|
||||
List<String> exclusions) throws IOException {
|
||||
|
||||
for (Entry<String, ClassReader> entry : classes.entrySet()) {
|
||||
ClassReader cr = entry.getValue();
|
||||
|
||||
String name = classNameToJavaPath(cr.getClassName());
|
||||
|
||||
FileWriter fw = null;
|
||||
try {
|
||||
fw = createWriter(baseDir, name);
|
||||
dumpClass(fw, cr, exclusions);
|
||||
} finally {
|
||||
fw.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FileWriter createWriter(File baseDir, String name) throws IOException {
|
||||
File f = new File(baseDir, name);
|
||||
f.getParentFile().mkdirs();
|
||||
|
||||
System.out.println("Writing " + f.getPath());
|
||||
|
||||
return new FileWriter(f);
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility method that converts a fully qualified java name into a JAR entry path
|
||||
* e.g. for the input "android.view.View" it returns "android/view/View.java"
|
||||
*/
|
||||
String classNameToJavaPath(String className) {
|
||||
return className.replace('.', '/').concat(".java");
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a source equivalent to the stubbed version of the class reader,
|
||||
* minus all exclusions
|
||||
*/
|
||||
void dumpClass(Writer fw, ClassReader cr, List<String> exclusions) {
|
||||
System.out.println("Dump " + cr.getClassName());
|
||||
|
||||
ClassVisitor javaWriter = new JavaSourcer(new Output(fw));
|
||||
ClassVisitor filter = new FilterClassAdapter(javaWriter, exclusions);
|
||||
cr.accept(filter, 0 /*flags*/);
|
||||
}
|
||||
|
||||
}
|
||||
139
tools/mkstubs/src/com/android/mkstubs/FilterClassAdapter.java
Normal file
139
tools/mkstubs/src/com/android/mkstubs/FilterClassAdapter.java
Normal file
@@ -0,0 +1,139 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import org.objectweb.asm.AnnotationVisitor;
|
||||
import org.objectweb.asm.Attribute;
|
||||
import org.objectweb.asm.ClassAdapter;
|
||||
import org.objectweb.asm.ClassVisitor;
|
||||
import org.objectweb.asm.FieldVisitor;
|
||||
import org.objectweb.asm.MethodVisitor;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* A class visitor that filters out all the referenced exclusions
|
||||
*/
|
||||
class FilterClassAdapter extends ClassAdapter {
|
||||
|
||||
private final List<String> mExclusions;
|
||||
|
||||
public FilterClassAdapter(ClassVisitor writer, List<String> exclusions) {
|
||||
super(writer);
|
||||
mExclusions = exclusions;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(int version, int access, String name, String signature,
|
||||
String superName, String[] interfaces) {
|
||||
|
||||
// TODO filter super type
|
||||
// TODO filter interfaces
|
||||
|
||||
super.visit(version, access, name, signature, superName, interfaces);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitEnd() {
|
||||
super.visitEnd();
|
||||
}
|
||||
|
||||
/**
|
||||
* Visits a field.
|
||||
*
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* Examples:
|
||||
* name = mArg
|
||||
* desc = Ljava/Lang/String;
|
||||
* signature = null (not a template) or template type
|
||||
*/
|
||||
@Override
|
||||
public FieldVisitor visitField(int access, String name, String desc,
|
||||
String signature, Object value) {
|
||||
// exclude private fields
|
||||
if ((access & Opcodes.ACC_PRIVATE) != 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// TODO filter on name
|
||||
|
||||
return super.visitField(access, name, desc, signature, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Visits a method.
|
||||
*
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* Examples:
|
||||
* name = <init>
|
||||
* desc = ()V
|
||||
* signature = null (not a template) or template type
|
||||
*/
|
||||
@Override
|
||||
public MethodVisitor visitMethod(int access, String name, String desc,
|
||||
String signature, String[] exceptions) {
|
||||
|
||||
// exclude private methods
|
||||
if ((access & Opcodes.ACC_PRIVATE) != 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// TODO filter exceptions: error if filtered exception is being used
|
||||
|
||||
// TODO filter on name; error if filtered desc or signatures is being used
|
||||
|
||||
return super.visitMethod(access, name, desc, signature, exceptions);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
|
||||
|
||||
// Filter on desc type
|
||||
return super.visitAnnotation(desc, visible);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitAttribute(Attribute attr) {
|
||||
// pass
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitInnerClass(String name, String outerName, String innerName, int access) {
|
||||
|
||||
// exclude private methods
|
||||
if ((access & Opcodes.ACC_PRIVATE) != 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO filter on name
|
||||
|
||||
super.visitInnerClass(name, outerName, innerName, access);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitOuterClass(String owner, String name, String desc) {
|
||||
// TODO Auto-generated method stub
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitSource(String source, String debug) {
|
||||
// pass
|
||||
}
|
||||
}
|
||||
165
tools/mkstubs/src/com/android/mkstubs/Main.java
Normal file
165
tools/mkstubs/src/com/android/mkstubs/Main.java
Normal file
@@ -0,0 +1,165 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import org.objectweb.asm.ClassReader;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Map;
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public class Main {
|
||||
|
||||
static class Params {
|
||||
private String mInputJarPath;
|
||||
private String mOutputJarPath;
|
||||
private ArrayList<String> mInclusions = new ArrayList<String>();
|
||||
private ArrayList<String> mExclusions = new ArrayList<String>();
|
||||
|
||||
public Params(String inputJarPath, String outputJarPath) {
|
||||
mInputJarPath = inputJarPath;
|
||||
mOutputJarPath = outputJarPath;
|
||||
}
|
||||
|
||||
public String getInputJarPath() {
|
||||
return mInputJarPath;
|
||||
}
|
||||
|
||||
public String getOutputJarPath() {
|
||||
return mOutputJarPath;
|
||||
}
|
||||
|
||||
public ArrayList<String> getExclusions() {
|
||||
return mExclusions;
|
||||
}
|
||||
|
||||
public ArrayList<String> getInclusions() {
|
||||
return mInclusions;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param args
|
||||
*/
|
||||
public static void main(String[] args) {
|
||||
|
||||
Main m = new Main();
|
||||
try {
|
||||
Params p = m.processArgs(args);
|
||||
m.process(p);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private Params processArgs(String[] args) throws IOException {
|
||||
|
||||
if (args.length < 2) {
|
||||
usage();
|
||||
}
|
||||
|
||||
Params p = new Params(args[0], args[1]);
|
||||
|
||||
for (int i = 2; i < args.length; i++) {
|
||||
String s = args[i];
|
||||
if (s.startsWith("@")) {
|
||||
addStringsFromFile(p, s.substring(1));
|
||||
} else if (s.startsWith("-")) {
|
||||
p.getExclusions().add(s.substring(1));
|
||||
} else if (s.startsWith("+")) {
|
||||
p.getInclusions().add(s.substring(1));
|
||||
}
|
||||
}
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
private void addStringsFromFile(Params p, String inputFile)
|
||||
throws IOException {
|
||||
BufferedReader br = null;
|
||||
try {
|
||||
br = new BufferedReader(new FileReader(inputFile));
|
||||
String line;
|
||||
while ((line = br.readLine()) != null) {
|
||||
line = line.trim();
|
||||
if (line.length() == 0) {
|
||||
continue;
|
||||
}
|
||||
char mode = line.charAt(0);
|
||||
line = line.substring(1).trim();
|
||||
|
||||
if (line.length() > 0) {
|
||||
// Keep all class names in ASM path-like format, e.g. android/view/View
|
||||
line = line.replace('.', '/');
|
||||
if (mode == '-') {
|
||||
p.getExclusions().add(line);
|
||||
} else if (mode == '+') {
|
||||
p.getInclusions().add(line);
|
||||
}
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
br.close();
|
||||
}
|
||||
}
|
||||
|
||||
private void usage() {
|
||||
System.out.println("Usage: mkstub input.jar output.jar [excluded-class @excluded-classes-file ...]");
|
||||
|
||||
System.out.println("Include syntax:\n" +
|
||||
"+com.package.* : whole package, with glob\n" +
|
||||
"+com.package.Class[$Inner] or ...Class*: whole classes with optional glob\n" +
|
||||
"Inclusion is not supported at method/field level.\n\n");
|
||||
|
||||
System.out.println("Exclude syntax:\n" +
|
||||
"-com.package.* : whole package, with glob\n" +
|
||||
"-com.package.Class[$Inner] or ...Class*: whole classes with optional glob\n" +
|
||||
"-com.package.Class#method: whole method or field\n" +
|
||||
"-com.package.Class#method(IILjava/lang/String;)V: specific method with signature.\n\n");
|
||||
System.exit(1);
|
||||
}
|
||||
|
||||
private void process(Params p) throws IOException {
|
||||
AsmAnalyzer aa = new AsmAnalyzer();
|
||||
Map<String, ClassReader> classes = aa.parseInputJar(p.getInputJarPath());
|
||||
|
||||
aa.filter(classes, p.getInclusions(), p.getExclusions());
|
||||
|
||||
AsmGenerator gen = new AsmGenerator();
|
||||
|
||||
// dump as Java source files, mostly for debugging
|
||||
File dst_src_dir = new File(p.getOutputJarPath() + File.separator + "sources");
|
||||
dst_src_dir.mkdir();
|
||||
gen.generateSource(dst_src_dir, classes, p.getExclusions());
|
||||
|
||||
}
|
||||
|
||||
/** @deprecated debug only */
|
||||
private void displayClasses(Map<String, ClassReader> classes) {
|
||||
for(String className : classes.keySet()) {
|
||||
System.out.println("Found " + className);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
104
tools/mkstubs/src/com/android/mkstubs/sourcer/AccessSourcer.java
Normal file
104
tools/mkstubs/src/com/android/mkstubs/sourcer/AccessSourcer.java
Normal file
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
* 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.Opcodes;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
class AccessSourcer {
|
||||
|
||||
private final Output mOutput;
|
||||
|
||||
public static int IS_CLASS = 1;
|
||||
public static int IS_FIELD = 2;
|
||||
public static int IS_METHOD = 4;
|
||||
|
||||
private enum Flag {
|
||||
ACC_PUBLIC(Opcodes.ACC_PUBLIC , IS_CLASS | IS_FIELD | IS_METHOD),
|
||||
ACC_PRIVATE(Opcodes.ACC_PRIVATE , IS_CLASS | IS_FIELD | IS_METHOD),
|
||||
ACC_PROTECTED(Opcodes.ACC_PROTECTED , IS_CLASS | IS_FIELD | IS_METHOD),
|
||||
ACC_STATIC(Opcodes.ACC_STATIC , IS_FIELD | IS_METHOD),
|
||||
ACC_FINAL(Opcodes.ACC_FINAL , IS_CLASS | IS_FIELD | IS_METHOD),
|
||||
ACC_SUPER(Opcodes.ACC_SUPER , IS_CLASS),
|
||||
ACC_SYNCHRONIZED(Opcodes.ACC_SYNCHRONIZED , IS_METHOD),
|
||||
ACC_VOLATILE(Opcodes.ACC_VOLATILE , IS_FIELD),
|
||||
ACC_BRIDGE(Opcodes.ACC_BRIDGE , IS_METHOD),
|
||||
ACC_VARARGS(Opcodes.ACC_VARARGS , IS_METHOD),
|
||||
ACC_TRANSIENT(Opcodes.ACC_TRANSIENT , IS_FIELD),
|
||||
ACC_NATIVE(Opcodes.ACC_NATIVE , IS_METHOD),
|
||||
ACC_INTERFACE(Opcodes.ACC_INTERFACE , IS_CLASS),
|
||||
ACC_ABSTRACT(Opcodes.ACC_ABSTRACT , IS_CLASS | IS_METHOD),
|
||||
ACC_STRICT(Opcodes.ACC_STRICT , IS_METHOD),
|
||||
ACC_SYNTHETIC(Opcodes.ACC_SYNTHETIC , IS_CLASS | IS_FIELD | IS_METHOD),
|
||||
ACC_ANNOTATION(Opcodes.ACC_ANNOTATION , IS_CLASS),
|
||||
ACC_ENUM(Opcodes.ACC_ENUM , IS_CLASS),
|
||||
ACC_DEPRECATED(Opcodes.ACC_DEPRECATED , IS_CLASS | IS_FIELD | IS_METHOD)
|
||||
;
|
||||
|
||||
private final int mValue;
|
||||
private final int mFilter;
|
||||
|
||||
private Flag(int value, int filter) {
|
||||
mValue = value;
|
||||
mFilter = filter;
|
||||
}
|
||||
|
||||
public int getValue() {
|
||||
return mValue;
|
||||
}
|
||||
|
||||
public int getFilter() {
|
||||
return mFilter;
|
||||
}
|
||||
|
||||
/** Transforms "ACC_PUBLIC" into "public" */
|
||||
@Override
|
||||
public String toString() {
|
||||
return super.toString().substring(4).toLowerCase();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public AccessSourcer(Output output) {
|
||||
mOutput = output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a list of access keywords, e.g. "public final".
|
||||
*
|
||||
* @param access The access mode, e.g. 33 or 18
|
||||
* @param filter One of {@link #IS_CLASS}, {@link #IS_FIELD} or {@link #IS_METHOD}, which
|
||||
* indicates the validity context.
|
||||
*/
|
||||
public void write(int access, int filter) {
|
||||
|
||||
boolean need_sep = false;
|
||||
|
||||
for (Flag f : Flag.values()) {
|
||||
if ((f.getFilter() & filter) != 0 && (access & f.getValue()) != 0) {
|
||||
if (need_sep) {
|
||||
mOutput.write(" ");
|
||||
}
|
||||
mOutput.write(f.toString());
|
||||
need_sep = true;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
class AnnotationSourcer implements AnnotationVisitor {
|
||||
|
||||
private final String mOpenChar;
|
||||
private final String mCloseChar;
|
||||
private final Output mOutput;
|
||||
private boolean mNeedClose;
|
||||
|
||||
public AnnotationSourcer(Output output) {
|
||||
this(output, false /*isArray*/);
|
||||
}
|
||||
|
||||
public AnnotationSourcer(Output output, boolean isArray) {
|
||||
mOutput = output;
|
||||
mOpenChar = isArray ? "[" : "(";
|
||||
mCloseChar = isArray ? "]" : ")";
|
||||
}
|
||||
|
||||
public void visit(String name, Object value) {
|
||||
startOpen();
|
||||
|
||||
if (name != null) {
|
||||
mOutput.write("%s=", name);
|
||||
}
|
||||
if (value != null) {
|
||||
mOutput.write(name.toString());
|
||||
}
|
||||
}
|
||||
|
||||
private void startOpen() {
|
||||
if (!mNeedClose) {
|
||||
mNeedClose = true;
|
||||
mOutput.write(mOpenChar);
|
||||
}
|
||||
}
|
||||
|
||||
public void visitEnd() {
|
||||
if (mNeedClose) {
|
||||
mOutput.write(mCloseChar);
|
||||
}
|
||||
mOutput.write("\n");
|
||||
}
|
||||
|
||||
public AnnotationVisitor visitAnnotation(String name, String desc) {
|
||||
startOpen();
|
||||
|
||||
mOutput.write("@%s", name);
|
||||
return this;
|
||||
}
|
||||
|
||||
public AnnotationVisitor visitArray(String name) {
|
||||
startOpen();
|
||||
return new AnnotationSourcer(mOutput, true /*isArray*/);
|
||||
}
|
||||
|
||||
public void visitEnum(String name, String desc, String value) {
|
||||
mOutput.write("/* annotation enum not supported: %s */\n", name);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* 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.FieldVisitor;
|
||||
import org.objectweb.asm.signature.SignatureReader;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
class FieldSourcer implements FieldVisitor {
|
||||
|
||||
private final Output mOutput;
|
||||
private final int mAccess;
|
||||
private final String mName;
|
||||
private final String mDesc;
|
||||
private final String mSignature;
|
||||
|
||||
public FieldSourcer(Output output, int access, String name, String desc, String signature) {
|
||||
mOutput = output;
|
||||
mAccess = access;
|
||||
mName = name;
|
||||
mDesc = desc;
|
||||
mSignature = signature;
|
||||
}
|
||||
|
||||
public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
|
||||
mOutput.write("@%s", desc);
|
||||
return new AnnotationSourcer(mOutput);
|
||||
}
|
||||
|
||||
public void visitAttribute(Attribute attr) {
|
||||
mOutput.write("%s /* non-standard attribute */ ", attr.type);
|
||||
}
|
||||
|
||||
public void visitEnd() {
|
||||
// Need to write type and field name after the annotations and attributes.
|
||||
|
||||
AccessSourcer as = new AccessSourcer(mOutput);
|
||||
as.write(mAccess, AccessSourcer.IS_FIELD);
|
||||
|
||||
if (mSignature == null) {
|
||||
mOutput.write(" %s", mOutput.decodeDesc(mDesc));
|
||||
} else {
|
||||
mOutput.write(" ");
|
||||
SignatureReader sigReader = new SignatureReader(mSignature);
|
||||
SignatureSourcer sigSourcer = new SignatureSourcer();
|
||||
sigReader.acceptType(sigSourcer);
|
||||
mOutput.write(sigSourcer.toString());
|
||||
}
|
||||
|
||||
mOutput.write(" %s", mName);
|
||||
|
||||
mOutput.write(";\n");
|
||||
}
|
||||
|
||||
}
|
||||
139
tools/mkstubs/src/com/android/mkstubs/sourcer/JavaSourcer.java
Normal file
139
tools/mkstubs/src/com/android/mkstubs/sourcer/JavaSourcer.java
Normal file
@@ -0,0 +1,139 @@
|
||||
/*
|
||||
* 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.ClassVisitor;
|
||||
import org.objectweb.asm.FieldVisitor;
|
||||
import org.objectweb.asm.MethodVisitor;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
import org.objectweb.asm.signature.SignatureReader;
|
||||
|
||||
/**
|
||||
* A class visitor that rewrites a java source
|
||||
*/
|
||||
public class JavaSourcer implements ClassVisitor {
|
||||
|
||||
private final Output mOutput;
|
||||
private final AccessSourcer mAccessSourcer;
|
||||
private String mClassName;
|
||||
|
||||
public JavaSourcer(Output output) {
|
||||
mOutput = output;
|
||||
mAccessSourcer = new AccessSourcer(mOutput);
|
||||
}
|
||||
|
||||
/* Examples:
|
||||
* name = com/foo/MyClass
|
||||
* signature = null (if not generic)
|
||||
* superName = java/lang/Object
|
||||
* interfaces = [ java/lang/Runnable ... ]
|
||||
*/
|
||||
public void visit(int version, int access, String name, String signature,
|
||||
String superName, String[] interfaces) {
|
||||
|
||||
String pkg = name.substring(0, name.lastIndexOf('/')).replace('/', '.');
|
||||
mClassName = name.substring(name.lastIndexOf('/') + 1);
|
||||
|
||||
mOutput.write("package %s;\n", pkg);
|
||||
|
||||
// dump access keywords. Note: do not dump "super" here
|
||||
mAccessSourcer.write(access & ~Opcodes.ACC_SUPER, AccessSourcer.IS_CLASS);
|
||||
|
||||
// write class name
|
||||
mOutput.write(" class %s", mClassName);
|
||||
|
||||
if (signature != null) {
|
||||
// write template formal definition and super type
|
||||
SignatureReader sigReader = new SignatureReader(signature);
|
||||
SignatureSourcer sigSourcer = new SignatureSourcer();
|
||||
sigReader.accept(sigSourcer);
|
||||
|
||||
if (sigSourcer.hasFormalsContent()) {
|
||||
mOutput.write(sigSourcer.formalsToString());
|
||||
}
|
||||
|
||||
mOutput.write(" extends %s", sigSourcer.getSuperClass().toString());
|
||||
|
||||
} else {
|
||||
// write non-generic super type
|
||||
mOutput.write(" extends %s", superName.replace('/', '.'));
|
||||
}
|
||||
|
||||
// write interfaces defined, if any
|
||||
if (interfaces != null && interfaces.length > 0) {
|
||||
mOutput.write(" implements ");
|
||||
boolean need_sep = false;
|
||||
for (String i : interfaces) {
|
||||
if (need_sep) {
|
||||
mOutput.write(", ");
|
||||
}
|
||||
mOutput.write(i.replace('/', '.'));
|
||||
need_sep = true;
|
||||
}
|
||||
}
|
||||
|
||||
// open class body
|
||||
mOutput.write(" {\n");
|
||||
}
|
||||
|
||||
public void visitEnd() {
|
||||
mOutput.write("}\n");
|
||||
}
|
||||
|
||||
public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
|
||||
mOutput.write("@%s", desc);
|
||||
return new AnnotationSourcer(mOutput);
|
||||
}
|
||||
|
||||
public void visitAttribute(Attribute attr) {
|
||||
mOutput.write("%s /* non-standard class attribute */ ", attr.type);
|
||||
}
|
||||
|
||||
|
||||
public FieldVisitor visitField(int access, String name, String desc, String signature,
|
||||
Object value) {
|
||||
// skip synthetic fields
|
||||
if ((access & Opcodes.ACC_SYNTHETIC) != 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return new FieldSourcer(mOutput, access, name, desc, signature);
|
||||
}
|
||||
|
||||
public MethodVisitor visitMethod(int access, String name, String desc, String signature,
|
||||
String[] exceptions) {
|
||||
|
||||
// Visit the method and dump its stub.
|
||||
return new MethodSourcer(mOutput, mClassName, access, name, desc, signature, exceptions);
|
||||
}
|
||||
|
||||
public void visitInnerClass(String name, String outerName, String innerName, int access) {
|
||||
// Skip inner classes. This just indicates there's an inner class definition but
|
||||
// they are visited at the top level as separate classes.
|
||||
}
|
||||
|
||||
public void visitOuterClass(String owner, String name, String desc) {
|
||||
// Skip outer classes.
|
||||
}
|
||||
|
||||
public void visitSource(String source, String debug) {
|
||||
// Skip source information.
|
||||
}
|
||||
|
||||
}
|
||||
235
tools/mkstubs/src/com/android/mkstubs/sourcer/MethodSourcer.java
Normal file
235
tools/mkstubs/src/com/android/mkstubs/sourcer/MethodSourcer.java
Normal file
@@ -0,0 +1,235 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
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
|
||||
}
|
||||
|
||||
}
|
||||
57
tools/mkstubs/src/com/android/mkstubs/sourcer/Output.java
Normal file
57
tools/mkstubs/src/com/android/mkstubs/sourcer/Output.java
Normal file
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* 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.Type;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Writer;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public class Output {
|
||||
|
||||
private final Writer mWriter;
|
||||
|
||||
public Output(Writer writer) {
|
||||
mWriter = writer;
|
||||
}
|
||||
|
||||
public void write(String format, Object... args) {
|
||||
try {
|
||||
mWriter.write(String.format(format, args));
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public void write(char c) {
|
||||
write(Character.toString(c));
|
||||
}
|
||||
|
||||
public void write(StringBuilder sb) {
|
||||
write(sb.toString());
|
||||
}
|
||||
|
||||
|
||||
public String decodeDesc(String desc) {
|
||||
return Type.getType(desc).getClassName();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,268 @@
|
||||
/*
|
||||
* 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.Type;
|
||||
import org.objectweb.asm.signature.SignatureReader;
|
||||
import org.objectweb.asm.signature.SignatureVisitor;
|
||||
import org.objectweb.asm.signature.SignatureWriter;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* Note: most of the implementation is a duplicate of
|
||||
* ASM's SignatureWriter with some slight variations.
|
||||
* <p/>
|
||||
* Note: When processing a method's signature, the signature order is the
|
||||
* reverse of the source order, e.g. it is (parameters)return-type where
|
||||
* we want to generate "return-type method-name (parameters)".
|
||||
* So in this case the return-type and parameters are not output directly
|
||||
* but are instead accumulated in internal variables.
|
||||
*/
|
||||
class SignatureSourcer implements SignatureVisitor {
|
||||
|
||||
/**
|
||||
* Buffer used to construct the signature.
|
||||
*/
|
||||
private final StringBuilder mBuf = new StringBuilder();
|
||||
|
||||
/**
|
||||
* Buffer used to construct the formals signature.
|
||||
*/
|
||||
private final StringBuilder mFormalsBuf = new StringBuilder();
|
||||
|
||||
/**
|
||||
* Indicates if the signature is currently processing formal type parameters.
|
||||
*/
|
||||
private boolean mWritingFormals;
|
||||
|
||||
/**
|
||||
* Stack used to keep track of class types that have arguments. Each element
|
||||
* of this stack is a boolean encoded in one bit. The top of the stack is
|
||||
* the lowest order bit. Pushing false = *2, pushing true = *2+1, popping =
|
||||
* /2.
|
||||
*/
|
||||
private int mArgumentStack;
|
||||
|
||||
private SignatureSourcer mReturnType;
|
||||
|
||||
private SignatureSourcer mSuperClass;
|
||||
|
||||
private ArrayList<SignatureSourcer> mParameters = new ArrayList<SignatureSourcer>();
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Constructs a new {@link SignatureWriter} object.
|
||||
*/
|
||||
public SignatureSourcer() {
|
||||
}
|
||||
|
||||
private StringBuilder getBuf() {
|
||||
if (mWritingFormals) {
|
||||
return mFormalsBuf;
|
||||
} else {
|
||||
return mBuf;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Contains the whole signature type when called by
|
||||
* {@link SignatureReader#acceptType(SignatureVisitor)} or just the formals if
|
||||
* called by {@link SignatureReader#accept(SignatureVisitor)}.
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return mBuf.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Will be non-null if a return type was processed
|
||||
* by {@link SignatureReader#accept(SignatureVisitor)}
|
||||
*/
|
||||
public SignatureSourcer getReturnType() {
|
||||
return mReturnType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Will be non-empty if a parameters were processed
|
||||
* by {@link SignatureReader#accept(SignatureVisitor)}
|
||||
*/
|
||||
public ArrayList<SignatureSourcer> getParameters() {
|
||||
return mParameters;
|
||||
}
|
||||
|
||||
/**
|
||||
* True if the signature contains formal type parameters, which are available
|
||||
* via {@link #formalsToString()} after calling {@link SignatureReader#accept(SignatureVisitor)}
|
||||
*/
|
||||
public boolean hasFormalsContent() {
|
||||
return mFormalsBuf.length() > 0;
|
||||
}
|
||||
|
||||
public String formalsToString() {
|
||||
return mFormalsBuf.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Will be non-null if a super class was processed
|
||||
* by {@link SignatureReader#accept(SignatureVisitor)}
|
||||
*/
|
||||
public SignatureSourcer getSuperClass() {
|
||||
return mSuperClass;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Implementation of the SignatureVisitor interface
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
public void visitFormalTypeParameter(final String name) {
|
||||
if (!mWritingFormals) {
|
||||
mWritingFormals = true;
|
||||
getBuf().append('<');
|
||||
} else {
|
||||
getBuf().append(", ");
|
||||
}
|
||||
getBuf().append(name);
|
||||
getBuf().append(" extends ");
|
||||
}
|
||||
|
||||
public SignatureVisitor visitClassBound() {
|
||||
// we don't differentiate between visiting a sub class or interface type
|
||||
return this;
|
||||
}
|
||||
|
||||
public SignatureVisitor visitInterfaceBound() {
|
||||
// we don't differentiate between visiting a sub class or interface type
|
||||
return this;
|
||||
}
|
||||
|
||||
public SignatureVisitor visitSuperclass() {
|
||||
endFormals();
|
||||
SignatureSourcer sourcer = new SignatureSourcer();
|
||||
assert mSuperClass == null;
|
||||
mSuperClass = sourcer;
|
||||
return sourcer;
|
||||
}
|
||||
|
||||
public SignatureVisitor visitInterface() {
|
||||
return this;
|
||||
}
|
||||
|
||||
public SignatureVisitor visitParameterType() {
|
||||
endFormals();
|
||||
SignatureSourcer sourcer = new SignatureSourcer();
|
||||
mParameters.add(sourcer);
|
||||
return sourcer;
|
||||
}
|
||||
|
||||
public SignatureVisitor visitReturnType() {
|
||||
endFormals();
|
||||
SignatureSourcer sourcer = new SignatureSourcer();
|
||||
assert mReturnType == null;
|
||||
mReturnType = sourcer;
|
||||
return sourcer;
|
||||
}
|
||||
|
||||
public SignatureVisitor visitExceptionType() {
|
||||
getBuf().append('^');
|
||||
return this;
|
||||
}
|
||||
|
||||
public void visitBaseType(final char descriptor) {
|
||||
getBuf().append(Type.getType(Character.toString(descriptor)).getClassName());
|
||||
}
|
||||
|
||||
public void visitTypeVariable(final String name) {
|
||||
getBuf().append(name.replace('/', '.'));
|
||||
}
|
||||
|
||||
public SignatureVisitor visitArrayType() {
|
||||
getBuf().append('[');
|
||||
return this;
|
||||
}
|
||||
|
||||
public void visitClassType(final String name) {
|
||||
getBuf().append(name.replace('/', '.'));
|
||||
mArgumentStack *= 2;
|
||||
}
|
||||
|
||||
public void visitInnerClassType(final String name) {
|
||||
endArguments();
|
||||
getBuf().append('.');
|
||||
getBuf().append(name.replace('/', '.'));
|
||||
mArgumentStack *= 2;
|
||||
}
|
||||
|
||||
public void visitTypeArgument() {
|
||||
if (mArgumentStack % 2 == 0) {
|
||||
++mArgumentStack;
|
||||
getBuf().append('<');
|
||||
} else {
|
||||
getBuf().append(", ");
|
||||
}
|
||||
getBuf().append('*');
|
||||
}
|
||||
|
||||
public SignatureVisitor visitTypeArgument(final char wildcard) {
|
||||
if (mArgumentStack % 2 == 0) {
|
||||
++mArgumentStack;
|
||||
getBuf().append('<');
|
||||
} else {
|
||||
getBuf().append(", ");
|
||||
}
|
||||
if (wildcard != '=') {
|
||||
if (wildcard == '+') {
|
||||
getBuf().append("? extends ");
|
||||
} else if (wildcard == '-') {
|
||||
getBuf().append("? super ");
|
||||
} else {
|
||||
// can this happen?
|
||||
getBuf().append(wildcard);
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public void visitEnd() {
|
||||
endArguments();
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Utility methods
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Ends the formal type parameters section of the signature.
|
||||
*/
|
||||
private void endFormals() {
|
||||
if (mWritingFormals) {
|
||||
getBuf().append('>');
|
||||
mWritingFormals = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Ends the type arguments of a class or inner class type.
|
||||
*/
|
||||
private void endArguments() {
|
||||
if (mArgumentStack % 2 != 0) {
|
||||
getBuf().append('>');
|
||||
}
|
||||
mArgumentStack /= 2;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.objectweb.asm.ClassReader;
|
||||
|
||||
import java.io.StringWriter;
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public class AsmGeneratorTest {
|
||||
|
||||
private AsmGenerator mGen;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
mGen = new AsmGenerator();
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testDumpClass() throws Exception {
|
||||
StringWriter sw = new StringWriter();
|
||||
ClassReader cr = new ClassReader("data/TestBaseClass");
|
||||
|
||||
mGen.dumpClass(sw, cr, new ArrayList<String>());
|
||||
|
||||
String s = sw.toString();
|
||||
Assert.assertNotNull(s);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
|
||||
public class FilterClassAdapterTest {
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* 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.junit.After;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
|
||||
import java.io.StringWriter;
|
||||
|
||||
public class AccessSourcerTest {
|
||||
|
||||
private StringWriter mWriter;
|
||||
private AccessSourcer mSourcer;
|
||||
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
mWriter = new StringWriter();
|
||||
mSourcer = new AccessSourcer(new Output(mWriter));
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
mWriter = null;
|
||||
mSourcer = null;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAbstractPublic() throws Exception {
|
||||
mSourcer.write(Opcodes.ACC_ABSTRACT | Opcodes.ACC_PUBLIC, AccessSourcer.IS_CLASS);
|
||||
|
||||
String s = mWriter.toString();
|
||||
Assert.assertEquals("public abstract", s);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPrivateFinalStatic() throws Exception {
|
||||
mSourcer.write(Opcodes.ACC_PRIVATE | Opcodes.ACC_FINAL | Opcodes.ACC_STATIC,
|
||||
AccessSourcer.IS_METHOD);
|
||||
|
||||
String s = mWriter.toString();
|
||||
Assert.assertEquals("private static final", s);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* 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.junit.After;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
|
||||
import java.io.StringWriter;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public class FieldSourcerTest {
|
||||
|
||||
private StringWriter mWriter;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
mWriter = new StringWriter();
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
mWriter = null;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStringField() throws Exception {
|
||||
|
||||
FieldSourcer fs = new FieldSourcer(new Output(mWriter),
|
||||
Opcodes.ACC_PUBLIC, // access
|
||||
"mArg", // name
|
||||
"Ljava/lang/String;", // desc
|
||||
null // signature
|
||||
);
|
||||
fs.visitEnd();
|
||||
|
||||
String s = mWriter.toString();
|
||||
Assert.assertEquals("public java.lang.String mArg;\n", s);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTemplateTypeField() throws Exception {
|
||||
|
||||
FieldSourcer fs = new FieldSourcer(new Output(mWriter),
|
||||
Opcodes.ACC_PRIVATE | Opcodes.ACC_FINAL, // access
|
||||
"mList", // name
|
||||
"Ljava/util/ArrayList;", // desc
|
||||
"Ljava/util/ArrayList<Ljava/lang/String;>;" // signature
|
||||
);
|
||||
fs.visitEnd();
|
||||
|
||||
String s = mWriter.toString();
|
||||
Assert.assertEquals("private final java.util.ArrayList<java.lang.String> mList;\n", s);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,139 @@
|
||||
/*
|
||||
* 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.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.objectweb.asm.ClassReader;
|
||||
|
||||
import java.io.StringWriter;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public class JavaSourcerTest extends TestHelper {
|
||||
|
||||
/**
|
||||
* @throws java.lang.Exception
|
||||
*/
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws java.lang.Exception
|
||||
*/
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBaseClassSource() throws Exception {
|
||||
StringWriter sw = new StringWriter();
|
||||
ClassReader cr = new ClassReader("data/TestBaseClass");
|
||||
|
||||
JavaSourcer jw = new JavaSourcer(new Output(sw));
|
||||
cr.accept(jw, 0);
|
||||
|
||||
assertSourceEquals(
|
||||
"package data;\n" +
|
||||
"public class TestBaseClass extends java.lang.Object implements java.lang.Runnable {\n" +
|
||||
"\n" +
|
||||
" private final java.lang.String mArg;\n" +
|
||||
" \n" +
|
||||
" public TestBaseClass() {\n" +
|
||||
" throw new RuntimeException(\"Stub\");" +
|
||||
" }\n" +
|
||||
" public TestBaseClass(java.lang.String arg0) {\n" +
|
||||
" throw new RuntimeException(\"Stub\");" +
|
||||
" }\n" +
|
||||
" public java.lang.String getArg() {\n" +
|
||||
" throw new RuntimeException(\"Stub\");" +
|
||||
" }\n" +
|
||||
" public void run() {\n" +
|
||||
" throw new RuntimeException(\"Stub\");" +
|
||||
" }\n" +
|
||||
"}",
|
||||
sw.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInnerClassSource() throws Exception {
|
||||
StringWriter sw = new StringWriter();
|
||||
ClassReader cr = new ClassReader("data/TestInnerClass");
|
||||
|
||||
JavaSourcer jw = new JavaSourcer(new Output(sw));
|
||||
cr.accept(jw, 0);
|
||||
|
||||
assertSourceEquals(
|
||||
"package data;\n" +
|
||||
"public class TestInnerClass extends java.lang.Object {\n" +
|
||||
" private final java.lang.String mArg;\n" +
|
||||
" public TestInnerClass() {\n" +
|
||||
" throw new RuntimeException(\"Stub\");\n" +
|
||||
" }\n" +
|
||||
" public TestInnerClass(java.lang.String arg0) {\n" +
|
||||
" throw new RuntimeException(\"Stub\");\n" +
|
||||
" }\n" +
|
||||
" public java.lang.String getArg() {\n" +
|
||||
" throw new RuntimeException(\"Stub\");\n" +
|
||||
" }\n" +
|
||||
" public data.TestInnerClass$InnerPubClass getInnerPubClass() {\n" +
|
||||
" throw new RuntimeException(\"Stub\");\n" +
|
||||
" }\n" +
|
||||
"}",
|
||||
sw.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTemplateClassSource() throws Exception {
|
||||
StringWriter sw = new StringWriter();
|
||||
ClassReader cr = new ClassReader("data/TestTemplateClass");
|
||||
|
||||
JavaSourcer jw = new JavaSourcer(new Output(sw));
|
||||
cr.accept(jw, 0);
|
||||
|
||||
assertSourceEquals(
|
||||
"package data;\n" +
|
||||
"public class TestTemplateClass<T extends java.io.InputStream, U extends java.lang.Object> extends java.lang.Object {\n" +
|
||||
" private final java.util.Map<T, U> mMap_T_U;\n" +
|
||||
" public java.util.Map<java.util.ArrayList<T>, java.util.Map<java.lang.String, java.util.ArrayList<U>>> mMap_T_S_U;\n" +
|
||||
" public TestTemplateClass() {\n" +
|
||||
" throw new RuntimeException(\"Stub\");\n" +
|
||||
" }\n" +
|
||||
" public java.util.Map<T, U> getMap_T_U() {\n" +
|
||||
" throw new RuntimeException(\"Stub\");\n" +
|
||||
" }\n" +
|
||||
" public java.util.Map<java.util.ArrayList<T>, java.util.Map<java.lang.String, java.util.ArrayList<U>>> getMap_T_S_U() {\n" +
|
||||
" throw new RuntimeException(\"Stub\");\n" +
|
||||
" }\n" +
|
||||
" public void draw(java.util.List<? extends org.w3c.dom.css.Rect> arg0) {\n" +
|
||||
" throw new RuntimeException(\"Stub\");\n" +
|
||||
" }\n" +
|
||||
" public static <T extends java.lang.Comparable<? super T>> void sort(java.util.List<T> arg0) {\n" +
|
||||
" throw new RuntimeException(\"Stub\");\n" +
|
||||
" }\n" +
|
||||
" public <X extends T, Y extends java.lang.Object> void getMap(java.util.List<T> arg0, java.util.Map<T, U> arg1, java.util.Map<X, java.util.Set<? super Y>> arg2) {\n" +
|
||||
" throw new RuntimeException(\"Stub\");\n" +
|
||||
" }\n" +
|
||||
"}",
|
||||
sw.toString());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
* 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.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
|
||||
import java.io.StringWriter;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public class MethodSourcerTest extends TestHelper {
|
||||
|
||||
private StringWriter mWriter;
|
||||
private Output mOutput;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
mWriter = new StringWriter();
|
||||
mOutput = new Output(mWriter);
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
mWriter = null;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testVoid() {
|
||||
MethodSourcer m = new MethodSourcer(mOutput,
|
||||
"foo", //classname
|
||||
Opcodes.ACC_PUBLIC, //access
|
||||
"testVoid", //name
|
||||
"()V", //desc
|
||||
null, //signature
|
||||
null); //exception
|
||||
m.visitEnd();
|
||||
|
||||
assertSourceEquals(
|
||||
"public void testVoid() { }",
|
||||
mWriter.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testVoidThrow() {
|
||||
MethodSourcer m = new MethodSourcer(mOutput,
|
||||
"foo", //classname
|
||||
Opcodes.ACC_PUBLIC, //access
|
||||
"testVoid", //name
|
||||
"()V", //desc
|
||||
null, //signature
|
||||
new String[] { "java/lang/Exception" }); //exception
|
||||
m.visitEnd();
|
||||
|
||||
assertSourceEquals(
|
||||
"public void testVoid() throws java.lang.Exception { }",
|
||||
mWriter.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReturnMap() {
|
||||
MethodSourcer m = new MethodSourcer(mOutput,
|
||||
"foo", //classname
|
||||
Opcodes.ACC_PUBLIC, //access
|
||||
"getMap_T_U", //name
|
||||
"()Ljava/util/Map;", //desc
|
||||
"()Ljava/util/Map<TT;TU;>;", //signature
|
||||
null); //exception
|
||||
m.visitEnd();
|
||||
|
||||
assertSourceEquals(
|
||||
"public java.util.Map<T, U> getMap_T_U() { }",
|
||||
mWriter.toString());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,146 @@
|
||||
/*
|
||||
* 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.junit.After;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.objectweb.asm.signature.SignatureReader;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public class SignatureSourcerTest {
|
||||
|
||||
private SignatureSourcer mSourcer;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
mSourcer = new SignatureSourcer();
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReturnMapNoArgs() {
|
||||
SignatureReader reader = new SignatureReader(
|
||||
"()Ljava/util/Map<Ljava/util/ArrayList<TT;>;Ljava/util/Map<Ljava/lang/String;Ljava/util/ArrayList<TU;>;>;>;");
|
||||
reader.accept(mSourcer);
|
||||
String result = mSourcer.getReturnType().toString();
|
||||
|
||||
Assert.assertEquals(
|
||||
"java.util.Map<java.util.ArrayList<T>, java.util.Map<java.lang.String, java.util.ArrayList<U>>>",
|
||||
result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReturnVoid() {
|
||||
SignatureReader reader = new SignatureReader(
|
||||
"(Ljava/util/List<+Lorg/w3c/dom/css/Rect;>;)V");
|
||||
reader.accept(mSourcer);
|
||||
String result = mSourcer.getReturnType().toString();
|
||||
|
||||
Assert.assertEquals(
|
||||
"void",
|
||||
result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSimpleArg() {
|
||||
SignatureReader reader = new SignatureReader(
|
||||
"(Ljava/util/List<+Lorg/w3c/dom/css/Rect;>;)V");
|
||||
reader.accept(mSourcer);
|
||||
|
||||
ArrayList<SignatureSourcer> params = mSourcer.getParameters();
|
||||
Assert.assertNotNull(params);
|
||||
|
||||
String[] array = toStringArray(params);
|
||||
|
||||
Assert.assertArrayEquals(
|
||||
new String[] { "java.util.List<? extends org.w3c.dom.css.Rect>" },
|
||||
array);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFormalParameters1() {
|
||||
SignatureReader reader = new SignatureReader("<X:TT;Y:Ljava/lang/Object;>()V");
|
||||
reader.accept(mSourcer);
|
||||
|
||||
Assert.assertTrue(mSourcer.hasFormalsContent());
|
||||
|
||||
String result = mSourcer.formalsToString();
|
||||
Assert.assertEquals(
|
||||
"<X extends T, Y extends java.lang.Object>",
|
||||
result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFormalParameters2() {
|
||||
SignatureReader reader = new SignatureReader("<T::Ljava/lang/Comparable<-TT;>;>(Ljava/util/List<TT;>;)V");
|
||||
reader.accept(mSourcer);
|
||||
|
||||
Assert.assertTrue(mSourcer.hasFormalsContent());
|
||||
|
||||
String result = mSourcer.formalsToString();
|
||||
Assert.assertEquals(
|
||||
"<T extends java.lang.Comparable<? super T>>",
|
||||
result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testManyArgs() {
|
||||
SignatureReader reader = new SignatureReader(
|
||||
"<X:TT;Y:Ljava/lang/Object;>(Ljava/util/List<TT;>;Ljava/util/Map<TT;TU;>;Ljava/util/Map<TX;Ljava/util/Set<-TY;>;>;)V");
|
||||
reader.accept(mSourcer);
|
||||
|
||||
Assert.assertTrue(mSourcer.hasFormalsContent());
|
||||
String formals = mSourcer.formalsToString();
|
||||
Assert.assertEquals(
|
||||
"<X extends T, Y extends java.lang.Object>",
|
||||
formals);
|
||||
|
||||
String result = mSourcer.getReturnType().toString();
|
||||
Assert.assertEquals(
|
||||
"void",
|
||||
result);
|
||||
|
||||
ArrayList<SignatureSourcer> params = mSourcer.getParameters();
|
||||
Assert.assertNotNull(params);
|
||||
|
||||
String[] array = toStringArray(params);
|
||||
|
||||
Assert.assertArrayEquals(
|
||||
new String[] { "java.util.List<T>",
|
||||
"java.util.Map<T, U>",
|
||||
"java.util.Map<X, java.util.Set<? super Y>>" },
|
||||
array);
|
||||
}
|
||||
|
||||
private String[] toStringArray(ArrayList<?> params) {
|
||||
String[] array = new String[params.size()];
|
||||
for (int i = 0; i < params.size(); i++) {
|
||||
array[i] = params.get(i).toString();
|
||||
}
|
||||
return array;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* 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.junit.Assert;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
abstract class TestHelper {
|
||||
|
||||
/**
|
||||
* Test source equality after normalizing all whitespace.
|
||||
*/
|
||||
public void assertSourceEquals(String expected, String actual) {
|
||||
String en = expected.replaceAll("[\\s]+", " ").trim();
|
||||
String an = actual.replaceAll( "[\\s]+", " ").trim();
|
||||
|
||||
Assert.assertEquals(
|
||||
String.format("Source comparison failure: expected:<%s> but was:<%s>", expected, actual),
|
||||
en, an);
|
||||
}
|
||||
}
|
||||
42
tools/mkstubs/tests/data/TestBaseClass.java
Normal file
42
tools/mkstubs/tests/data/TestBaseClass.java
Normal file
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* 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 data;
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public class TestBaseClass implements Runnable {
|
||||
|
||||
private final String mArg;
|
||||
|
||||
public TestBaseClass() {
|
||||
throw new RuntimeException("Stub");
|
||||
}
|
||||
|
||||
public TestBaseClass(String arg) {
|
||||
mArg = arg;
|
||||
}
|
||||
|
||||
public String getArg() {
|
||||
return mArg;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public void run() {
|
||||
}
|
||||
}
|
||||
52
tools/mkstubs/tests/data/TestInnerClass.java
Normal file
52
tools/mkstubs/tests/data/TestInnerClass.java
Normal file
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* 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 data;
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public class TestInnerClass {
|
||||
|
||||
private final String mArg;
|
||||
|
||||
private class InnerPrivClass {
|
||||
}
|
||||
|
||||
public class InnerPubClass {
|
||||
}
|
||||
|
||||
private static final class InnerStaticClass {
|
||||
}
|
||||
|
||||
public TestInnerClass() {
|
||||
mArg = null;
|
||||
}
|
||||
|
||||
public TestInnerClass(String arg) {
|
||||
mArg = arg;
|
||||
}
|
||||
|
||||
public String getArg() {
|
||||
return mArg;
|
||||
}
|
||||
|
||||
public InnerPubClass getInnerPubClass() {
|
||||
return new InnerPubClass();
|
||||
}
|
||||
|
||||
}
|
||||
55
tools/mkstubs/tests/data/TestTemplateClass.java
Normal file
55
tools/mkstubs/tests/data/TestTemplateClass.java
Normal file
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* 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 data;
|
||||
|
||||
import org.w3c.dom.css.Rect;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public class TestTemplateClass<T extends InputStream, U> {
|
||||
|
||||
private final Map<T, U> mMap_T_U = null;
|
||||
|
||||
public Map<ArrayList<T>, Map<String, ArrayList<U>>> mMap_T_S_U = null;
|
||||
|
||||
public TestTemplateClass() {
|
||||
}
|
||||
|
||||
public Map<T, U> getMap_T_U() {
|
||||
return mMap_T_U;
|
||||
}
|
||||
|
||||
public Map<ArrayList<T>, Map<String, ArrayList<U>>> getMap_T_S_U() {
|
||||
return mMap_T_S_U;
|
||||
}
|
||||
|
||||
public void draw(List<? extends Rect> shape) {
|
||||
}
|
||||
|
||||
public static <T extends Comparable<? super T>> void sort(List<T> list) {
|
||||
}
|
||||
|
||||
public <X extends T, Y> void getMap(List<T> list, Map<T, U> tu, Map<X, Set<? super Y>> xy) {
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user