upload android base code part7
This commit is contained in:
parent
4e516ec6ed
commit
841ae54672
25229 changed files with 1709508 additions and 0 deletions
1
android/development/tools/mkstubs/.idea/.name
generated
Normal file
1
android/development/tools/mkstubs/.idea/.name
generated
Normal file
|
@ -0,0 +1 @@
|
|||
mstubs
|
80
android/development/tools/mkstubs/.idea/codeStyleSettings.xml
generated
Normal file
80
android/development/tools/mkstubs/.idea/codeStyleSettings.xml
generated
Normal file
|
@ -0,0 +1,80 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectCodeStyleSettingsManager">
|
||||
<option name="PER_PROJECT_SETTINGS">
|
||||
<value>
|
||||
<option name="FIELD_NAME_PREFIX" value="m" />
|
||||
<option name="STATIC_FIELD_NAME_PREFIX" value="s" />
|
||||
<option name="INSERT_INNER_CLASS_IMPORTS" value="true" />
|
||||
<option name="CLASS_COUNT_TO_USE_IMPORT_ON_DEMAND" value="999" />
|
||||
<option name="NAMES_COUNT_TO_USE_IMPORT_ON_DEMAND" value="999" />
|
||||
<option name="PACKAGES_TO_USE_IMPORT_ON_DEMAND">
|
||||
<value />
|
||||
</option>
|
||||
<option name="IMPORT_LAYOUT_TABLE">
|
||||
<value>
|
||||
<package name="com.android" withSubpackages="true" static="false" />
|
||||
<emptyLine />
|
||||
<package name="org" withSubpackages="true" static="false" />
|
||||
<emptyLine />
|
||||
<package name="android" withSubpackages="true" static="false" />
|
||||
<emptyLine />
|
||||
<package name="java" withSubpackages="true" static="false" />
|
||||
<emptyLine />
|
||||
<package name="" withSubpackages="true" static="false" />
|
||||
<emptyLine />
|
||||
<package name="" withSubpackages="true" static="true" />
|
||||
</value>
|
||||
</option>
|
||||
<option name="RIGHT_MARGIN" value="100" />
|
||||
<option name="WRAP_WHEN_TYPING_REACHES_RIGHT_MARGIN" value="true" />
|
||||
<option name="JD_ALIGN_PARAM_COMMENTS" value="false" />
|
||||
<option name="JD_ADD_BLANK_AFTER_PARM_COMMENTS" value="true" />
|
||||
<option name="JD_ADD_BLANK_AFTER_RETURN" value="true" />
|
||||
<option name="JD_DO_NOT_WRAP_ONE_LINE_COMMENTS" value="true" />
|
||||
<option name="WRAP_COMMENTS" value="true" />
|
||||
<JavaCodeStyleSettings>
|
||||
<option name="CLASS_NAMES_IN_JAVADOC" value="3" />
|
||||
</JavaCodeStyleSettings>
|
||||
<XML>
|
||||
<option name="XML_LEGACY_SETTINGS_IMPORTED" value="true" />
|
||||
</XML>
|
||||
<codeStyleSettings language="JAVA">
|
||||
<option name="ALIGN_MULTILINE_PARAMETERS" value="false" />
|
||||
<option name="CALL_PARAMETERS_WRAP" value="1" />
|
||||
<option name="METHOD_PARAMETERS_WRAP" value="1" />
|
||||
<option name="THROWS_LIST_WRAP" value="1" />
|
||||
<option name="EXTENDS_KEYWORD_WRAP" value="1" />
|
||||
<option name="THROWS_KEYWORD_WRAP" value="1" />
|
||||
<option name="BINARY_OPERATION_WRAP" value="1" />
|
||||
<option name="TERNARY_OPERATION_WRAP" value="1" />
|
||||
<option name="ARRAY_INITIALIZER_WRAP" value="1" />
|
||||
<option name="ASSIGNMENT_WRAP" value="1" />
|
||||
<option name="ASSERT_STATEMENT_WRAP" value="1" />
|
||||
<option name="IF_BRACE_FORCE" value="3" />
|
||||
<option name="DOWHILE_BRACE_FORCE" value="3" />
|
||||
<option name="WHILE_BRACE_FORCE" value="3" />
|
||||
<option name="FOR_BRACE_FORCE" value="3" />
|
||||
<arrangement>
|
||||
<groups>
|
||||
<group>
|
||||
<type>GETTERS_AND_SETTERS</type>
|
||||
<order>KEEP</order>
|
||||
</group>
|
||||
<group>
|
||||
<type>OVERRIDDEN_METHODS</type>
|
||||
<order>KEEP</order>
|
||||
</group>
|
||||
</groups>
|
||||
</arrangement>
|
||||
</codeStyleSettings>
|
||||
<codeStyleSettings language="XML">
|
||||
<indentOptions>
|
||||
<option name="CONTINUATION_INDENT_SIZE" value="4" />
|
||||
</indentOptions>
|
||||
</codeStyleSettings>
|
||||
</value>
|
||||
</option>
|
||||
<option name="USE_PER_PROJECT_SETTINGS" value="true" />
|
||||
</component>
|
||||
</project>
|
22
android/development/tools/mkstubs/.idea/compiler.xml
generated
Normal file
22
android/development/tools/mkstubs/.idea/compiler.xml
generated
Normal file
|
@ -0,0 +1,22 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="CompilerConfiguration">
|
||||
<resourceExtensions />
|
||||
<wildcardResourcePatterns>
|
||||
<entry name="!?*.java" />
|
||||
<entry name="!?*.form" />
|
||||
<entry name="!?*.class" />
|
||||
<entry name="!?*.groovy" />
|
||||
<entry name="!?*.scala" />
|
||||
<entry name="!?*.flex" />
|
||||
<entry name="!?*.kt" />
|
||||
<entry name="!?*.clj" />
|
||||
<entry name="!?*.aj" />
|
||||
</wildcardResourcePatterns>
|
||||
<annotationProcessing>
|
||||
<profile default="true" name="Default" enabled="false">
|
||||
<processorPath useClasspath="true" />
|
||||
</profile>
|
||||
</annotationProcessing>
|
||||
</component>
|
||||
</project>
|
9
android/development/tools/mkstubs/.idea/copyright/Android.xml
generated
Normal file
9
android/development/tools/mkstubs/.idea/copyright/Android.xml
generated
Normal file
|
@ -0,0 +1,9 @@
|
|||
<component name="CopyrightManager">
|
||||
<copyright>
|
||||
<option name="notice" value="Copyright (C) &#36;today.year 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." />
|
||||
<option name="keyword" value="Copyright" />
|
||||
<option name="allowReplaceKeyword" value="" />
|
||||
<option name="myName" value="Android" />
|
||||
<option name="myLocal" value="true" />
|
||||
</copyright>
|
||||
</component>
|
3
android/development/tools/mkstubs/.idea/copyright/profiles_settings.xml
generated
Normal file
3
android/development/tools/mkstubs/.idea/copyright/profiles_settings.xml
generated
Normal file
|
@ -0,0 +1,3 @@
|
|||
<component name="CopyrightManager">
|
||||
<settings default="Android" />
|
||||
</component>
|
6
android/development/tools/mkstubs/.idea/encodings.xml
generated
Normal file
6
android/development/tools/mkstubs/.idea/encodings.xml
generated
Normal file
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="Encoding">
|
||||
<file url="PROJECT" charset="UTF-8" />
|
||||
</component>
|
||||
</project>
|
14
android/development/tools/mkstubs/.idea/inspectionProfiles/Project_Default.xml
generated
Normal file
14
android/development/tools/mkstubs/.idea/inspectionProfiles/Project_Default.xml
generated
Normal file
|
@ -0,0 +1,14 @@
|
|||
<component name="InspectionProjectProfileManager">
|
||||
<profile version="1.0">
|
||||
<option name="myName" value="Project Default" />
|
||||
<inspection_tool class="LoggerInitializedWithForeignClass" enabled="false" level="WARNING" enabled_by_default="false">
|
||||
<option name="loggerClassName" value="org.apache.log4j.Logger,org.slf4j.LoggerFactory,org.apache.commons.logging.LogFactory,java.util.logging.Logger" />
|
||||
<option name="loggerFactoryMethodName" value="getLogger,getLogger,getLog,getLogger" />
|
||||
</inspection_tool>
|
||||
<inspection_tool class="WeakerAccess" enabled="false" level="WARNING" enabled_by_default="false">
|
||||
<option name="SUGGEST_PACKAGE_LOCAL_FOR_MEMBERS" value="true" />
|
||||
<option name="SUGGEST_PACKAGE_LOCAL_FOR_TOP_CLASSES" value="true" />
|
||||
<option name="SUGGEST_PRIVATE_FOR_INNERS" value="false" />
|
||||
</inspection_tool>
|
||||
</profile>
|
||||
</component>
|
7
android/development/tools/mkstubs/.idea/inspectionProfiles/profiles_settings.xml
generated
Normal file
7
android/development/tools/mkstubs/.idea/inspectionProfiles/profiles_settings.xml
generated
Normal file
|
@ -0,0 +1,7 @@
|
|||
<component name="InspectionProjectProfileManager">
|
||||
<settings>
|
||||
<option name="PROJECT_PROFILE" value="Project Default" />
|
||||
<option name="USE_PROJECT_PROFILE" value="true" />
|
||||
<version value="1.0" />
|
||||
</settings>
|
||||
</component>
|
19
android/development/tools/mkstubs/.idea/misc.xml
generated
Normal file
19
android/development/tools/mkstubs/.idea/misc.xml
generated
Normal file
|
@ -0,0 +1,19 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="EntryPointsManager">
|
||||
<entry_points version="2.0" />
|
||||
</component>
|
||||
<component name="ProjectLevelVcsManager" settingsEditedManually="false">
|
||||
<OptionsSetting value="true" id="Add" />
|
||||
<OptionsSetting value="true" id="Remove" />
|
||||
<OptionsSetting value="true" id="Checkout" />
|
||||
<OptionsSetting value="true" id="Update" />
|
||||
<OptionsSetting value="true" id="Status" />
|
||||
<OptionsSetting value="true" id="Edit" />
|
||||
<ConfirmationsSetting value="0" id="Add" />
|
||||
<ConfirmationsSetting value="0" id="Remove" />
|
||||
</component>
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" default="true" assert-keyword="true" jdk-15="true" project-jdk-name="1.8" project-jdk-type="JavaSDK">
|
||||
<output url="file://$PROJECT_DIR$/out" />
|
||||
</component>
|
||||
</project>
|
8
android/development/tools/mkstubs/.idea/modules.xml
generated
Normal file
8
android/development/tools/mkstubs/.idea/modules.xml
generated
Normal file
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/mkstubs.iml" filepath="$PROJECT_DIR$/mkstubs.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
6
android/development/tools/mkstubs/.idea/vcs.xml
generated
Normal file
6
android/development/tools/mkstubs/.idea/vcs.xml
generated
Normal file
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="$PROJECT_DIR$/../.." vcs="Git" />
|
||||
</component>
|
||||
</project>
|
28
android/development/tools/mkstubs/Android.mk
Normal file
28
android/development/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-5.2
|
||||
|
||||
LOCAL_MODULE := mkstubs
|
||||
|
||||
include $(BUILD_HOST_JAVA_LIBRARY)
|
||||
|
90
android/development/tools/mkstubs/README.txt
Normal file
90
android/development/tools/mkstubs/README.txt
Normal file
|
@ -0,0 +1,90 @@
|
|||
2009/04/20.
|
||||
|
||||
-------
|
||||
1- Goal
|
||||
-------
|
||||
|
||||
MkStub is small tool that takes a given JAR and filters all the private stuff we don't want to
|
||||
expose, e.g.:
|
||||
- remove all private members.
|
||||
- only include a subset of classes.
|
||||
- exclude specific classes, fields or methods.
|
||||
|
||||
Each method body is replaced by the bytecode for 'throw new RuntimeException("stub");'.
|
||||
|
||||
|
||||
--------
|
||||
2- Usage
|
||||
--------
|
||||
|
||||
To control it, you give it patterns like this:
|
||||
|
||||
+foo => accepts all items which signature is exactly "foo"
|
||||
+foo* => accepts all items which signature starts by "foo"
|
||||
-bar => rejects all items which signature is exactly "bar"
|
||||
-bar* => rejects all items which signature starts by "bar"
|
||||
|
||||
Signatures are defined by:
|
||||
- a package name, e.g. com.android.blah
|
||||
- a dot followed by a class name
|
||||
- a # followed by a field or method name
|
||||
- an internal "Java method signature" that define parameters types and return value.
|
||||
|
||||
Examples of signatures:
|
||||
com.android.blah
|
||||
com.android.blah.MyClass
|
||||
com.android.blah.MyClass$MyInnerClass
|
||||
com.android.blah.MyClass#mPrivateField
|
||||
com.android.blah.MyClass#getInternalStuff
|
||||
com.android.blah.MyClass#getInternalStuff(Ljava/lang/String;I)V
|
||||
|
||||
An example of configuration file:
|
||||
+com.android.blah
|
||||
-com.android.blah.MyClass$MyInnerClass
|
||||
-com.android.blah.MyClass#mPrivateField
|
||||
-com.android.blah.MyClass#getInternalStuff(Ljava/lang/String;I)V
|
||||
|
||||
This would include only the indicated package yet would totally exclude the inner class
|
||||
and the specific field and the method with the exact given signature.
|
||||
|
||||
|
||||
|
||||
To invoke MkStub, the syntax is:
|
||||
|
||||
$ java -jar mkstubs input.jar output.jar [@configfile -pattern +pattern ...]
|
||||
|
||||
|
||||
|
||||
--------------------
|
||||
3- Known Limitations
|
||||
--------------------
|
||||
|
||||
Most of the following limitations exist solely because of the short development time and
|
||||
because the tool was designed to solve one task and not just to be super generic. That means
|
||||
any limitation here can be easily lifted.
|
||||
|
||||
- The generated constructors are not proper. They do not invoke the matching super()
|
||||
before the generated throw exception. Any attempt to load such a class should trigger
|
||||
an error from the byte code verifier or the class loader.
|
||||
|
||||
- We do not currently check whether a class or method uses only included types.
|
||||
Suggestion: if type x.y.z is excluded, then any field, annotation, generic type,
|
||||
method parameter or return value that uses that type should generate a fatal error.
|
||||
|
||||
- We do not filter out private classes. Their .class will still be present in the
|
||||
output (and stubbed), unless they are explicitly excluded.
|
||||
This is not orthogonal to the fact that private fields and methods are automatically
|
||||
excluded.
|
||||
|
||||
- Private fields and methods are automatically excluded. There is no command line
|
||||
switch to prevent that.
|
||||
|
||||
- The stubbed source is always generated. For example if the output jar name is
|
||||
given as ~/somedir/myfinal.jar, there will be a directory created at
|
||||
~/somedir/myfinal.jar_sources that will contain the equivalent Java sources.
|
||||
There is not command line switch to prevent that.
|
||||
|
||||
- There is no attempt to match features or behavior with DroidDoc.
|
||||
|
||||
--
|
||||
end
|
1
android/development/tools/mkstubs/manifest.txt
Normal file
1
android/development/tools/mkstubs/manifest.txt
Normal file
|
@ -0,0 +1 @@
|
|||
Main-Class: com.android.mkstubs.Main
|
|
@ -0,0 +1,99 @@
|
|||
/*
|
||||
* 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.Main.Logger;
|
||||
|
||||
import org.objectweb.asm.ClassReader;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Enumeration;
|
||||
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;
|
||||
|
||||
/**
|
||||
* Analyzes an input Jar to get all the relevant classes according to the given filter.
|
||||
* <p/>
|
||||
* This is mostly a helper extracted for convenience. Callers will want to use
|
||||
* {@link #parseInputJar(String)} followed by {@link #filter(Map, Filter, Logger)}.
|
||||
*/
|
||||
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<>();
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters the set of classes. Removes all classes that should not be included in the
|
||||
* filter or that should be excluded. This modifies the map in-place.
|
||||
*
|
||||
* @param classes The in-out map of classes to examine and filter. The map is filtered
|
||||
* in-place.
|
||||
* @param filter A filter describing which classes to include and which ones to exclude.
|
||||
* @param log
|
||||
*/
|
||||
void filter(Map<String, ClassReader> classes, Filter filter, Logger log) {
|
||||
|
||||
Set<String> keys = classes.keySet();
|
||||
for(Iterator<String> it = keys.iterator(); it.hasNext(); ) {
|
||||
String key = it.next();
|
||||
|
||||
// TODO: We *could* filter out all private classes here: classes.get(key).getAccess().
|
||||
|
||||
// remove if we don't keep it
|
||||
if (!filter.accept(key)) {
|
||||
log.debug("- Remove class " + key);
|
||||
it.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,106 @@
|
|||
/*
|
||||
* 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 java.util.TreeSet;
|
||||
|
||||
/**
|
||||
* A "filter" holds the various patterns that MkStubs should accept (include)
|
||||
* or reject (exclude). Patterns can be of two kind:
|
||||
* <ul>
|
||||
* <li>Full patterns are simple string matches, similar to a "^pattern$" regex.
|
||||
* <li>Prefix patterns are partial string matches, similar to a "^pattern.*" regex.
|
||||
* </ul>
|
||||
* <p/>
|
||||
* The {@link #accept(String)} method examines a given string against the known
|
||||
* pattern to decide if it should be included.
|
||||
*/
|
||||
class Filter {
|
||||
private TreeSet<String> mIncludePrefix = new TreeSet<>();
|
||||
private TreeSet<String> mIncludeFull = new TreeSet<>();
|
||||
private TreeSet<String> mExcludePrefix = new TreeSet<>();
|
||||
private TreeSet<String> mExcludeFull = new TreeSet<>();
|
||||
|
||||
/**
|
||||
* Returns the set of all full patterns to be included.
|
||||
*/
|
||||
public TreeSet<String> getIncludeFull() {
|
||||
return mIncludeFull;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the set of all prefix patterns to be included.
|
||||
*/
|
||||
public TreeSet<String> getIncludePrefix() {
|
||||
return mIncludePrefix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the set of all full patterns to be excluded.
|
||||
*/
|
||||
public TreeSet<String> getExcludeFull() {
|
||||
return mExcludeFull;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the set of all prefix patterns to be excluded.
|
||||
*/
|
||||
public TreeSet<String> getExcludePrefix() {
|
||||
return mExcludePrefix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the given string passes the various include/exclude rules.
|
||||
* The matching is done as follows:
|
||||
* <ul>
|
||||
* <li> The string must match either a full include or a prefix include.
|
||||
* <li> The string must not match any full exclude nor any prefix exclude.
|
||||
* </ul>
|
||||
* @param s The string to accept or reject.
|
||||
* @return True if the string can be accepted, false if it must be rejected.
|
||||
*/
|
||||
public boolean accept(String s) {
|
||||
|
||||
// Check if it can be included.
|
||||
boolean accept = mIncludeFull.contains(s);
|
||||
if (!accept) {
|
||||
// Check for a prefix inclusion
|
||||
for (String prefix : mIncludePrefix) {
|
||||
if (s.startsWith(prefix)) {
|
||||
accept = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (accept) {
|
||||
// check for a full exclusion
|
||||
accept = !mExcludeFull.contains(s);
|
||||
}
|
||||
if (accept) {
|
||||
// or check for prefix exclusion
|
||||
for (String prefix : mExcludePrefix) {
|
||||
if (s.startsWith(prefix)) {
|
||||
accept = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return accept;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,167 @@
|
|||
/*
|
||||
* 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.Main.Logger;
|
||||
|
||||
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;
|
||||
|
||||
/**
|
||||
* A class visitor that filters out all members (fields, methods and inner classes) that are
|
||||
* either private, default-access or rejected by the {@link Filter}.
|
||||
*/
|
||||
class FilterClassAdapter extends ClassVisitor {
|
||||
|
||||
private final Logger mLog;
|
||||
private final Filter mFilter;
|
||||
private String mClassName;
|
||||
|
||||
public FilterClassAdapter(ClassVisitor writer, Filter filter, Logger log) {
|
||||
super(Main.ASM_VERSION, writer);
|
||||
mFilter = filter;
|
||||
mLog = log;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(int version, int access, String name, String signature,
|
||||
String superName, String[] interfaces) {
|
||||
|
||||
mClassName = name;
|
||||
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) {
|
||||
// only accept public/protected fields
|
||||
if ((access & (Opcodes.ACC_PUBLIC | Opcodes.ACC_PROTECTED)) == 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// filter on field name
|
||||
String filterName = String.format("%s#%s", mClassName, name);
|
||||
|
||||
if (!mFilter.accept(filterName)) {
|
||||
mLog.debug("- Remove field " + filterName);
|
||||
return null;
|
||||
}
|
||||
|
||||
// TODO we should produce an error if a filtered desc/signature is being used.
|
||||
|
||||
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) {
|
||||
|
||||
// only accept public/protected methods
|
||||
if ((access & (Opcodes.ACC_PUBLIC | Opcodes.ACC_PROTECTED)) == 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// filter on method name using the non-generic descriptor
|
||||
String filterName = String.format("%s#%s%s", mClassName, name, desc);
|
||||
|
||||
if (!mFilter.accept(filterName)) {
|
||||
mLog.debug("- Remove method " + filterName);
|
||||
return null;
|
||||
}
|
||||
|
||||
// filter on method name using the generic signature
|
||||
if (signature != null) {
|
||||
filterName = String.format("%s#%s%s", mClassName, name, signature);
|
||||
|
||||
if (!mFilter.accept(filterName)) {
|
||||
mLog.debug("- Remove method " + filterName);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO we should produce an error if a filtered desc/signature/exception is being used.
|
||||
|
||||
return super.visitMethod(access, name, desc, signature, exceptions);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
|
||||
|
||||
// TODO produce an error if a filtered annotation type is being used
|
||||
return super.visitAnnotation(desc, visible);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitAttribute(Attribute attr) {
|
||||
// pass
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitInnerClass(String name, String outerName, String innerName, int access) {
|
||||
|
||||
// only accept public/protected inner classes
|
||||
if ((access & (Opcodes.ACC_PUBLIC | Opcodes.ACC_PROTECTED)) == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// filter on name
|
||||
if (!mFilter.accept(name)) {
|
||||
return;
|
||||
}
|
||||
|
||||
super.visitInnerClass(name, outerName, innerName, access);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitOuterClass(String owner, String name, String desc) {
|
||||
// pass
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitSource(String source, String debug) {
|
||||
// pass
|
||||
}
|
||||
}
|
|
@ -0,0 +1,312 @@
|
|||
/*
|
||||
* 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 org.objectweb.asm.Opcodes;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
|
||||
|
||||
/**
|
||||
* Main entry point of the MkStubs app.
|
||||
* <p/>
|
||||
* For workflow details, see {@link #process(Params)}.
|
||||
*/
|
||||
public class Main {
|
||||
|
||||
public static final int ASM_VERSION = Opcodes.ASM5;
|
||||
|
||||
/**
|
||||
* A struct-like class to hold the various input values (e.g. command-line args)
|
||||
*/
|
||||
static class Params {
|
||||
private String mInputJarPath;
|
||||
private String mOutputJarPath;
|
||||
private Filter mFilter;
|
||||
private boolean mVerbose;
|
||||
private boolean mDumpSource;
|
||||
|
||||
public Params() {
|
||||
mFilter = new Filter();
|
||||
}
|
||||
|
||||
/** Sets the name of the input jar, where to read classes from. Must not be null. */
|
||||
public void setInputJarPath(String inputJarPath) {
|
||||
mInputJarPath = inputJarPath;
|
||||
}
|
||||
|
||||
/** Sets the name of the output jar, where to write classes to. Must not be null. */
|
||||
public void setOutputJarPath(String outputJarPath) {
|
||||
mOutputJarPath = outputJarPath;
|
||||
}
|
||||
|
||||
/** Returns the name of the input jar, where to read classes from. */
|
||||
public String getInputJarPath() {
|
||||
return mInputJarPath;
|
||||
}
|
||||
|
||||
/** Returns the name of the output jar, where to write classes to. */
|
||||
public String getOutputJarPath() {
|
||||
return mOutputJarPath;
|
||||
}
|
||||
|
||||
/** Returns the current instance of the filter, the include/exclude patterns. */
|
||||
public Filter getFilter() {
|
||||
return mFilter;
|
||||
}
|
||||
|
||||
/** Sets verbose mode on. Default is off. */
|
||||
public void setVerbose() {
|
||||
mVerbose = true;
|
||||
}
|
||||
|
||||
/** Returns true if verbose mode is on. */
|
||||
public boolean isVerbose() {
|
||||
return mVerbose;
|
||||
}
|
||||
|
||||
/** Sets dump source mode on. Default is off. */
|
||||
public void setDumpSource() {
|
||||
mDumpSource = true;
|
||||
}
|
||||
|
||||
/** Returns true if source should be dumped. */
|
||||
public boolean isDumpSource() {
|
||||
return mDumpSource;
|
||||
}
|
||||
}
|
||||
|
||||
/** Logger that writes on stdout depending a conditional verbose mode. */
|
||||
static class Logger {
|
||||
private final boolean mVerbose;
|
||||
|
||||
public Logger(boolean verbose) {
|
||||
mVerbose = verbose;
|
||||
}
|
||||
|
||||
/** Writes to stdout only in verbose mode. */
|
||||
public void debug(String msg, Object...params) {
|
||||
if (mVerbose) {
|
||||
System.out.println(String.format(msg, params));
|
||||
}
|
||||
}
|
||||
|
||||
/** Writes to stdout all the time. */
|
||||
public void info(String msg, Object...params) {
|
||||
System.out.println(String.format(msg, params));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Main entry point. Processes arguments then performs the "real" work.
|
||||
*/
|
||||
public static void main(String[] args) {
|
||||
Main m = new Main();
|
||||
try {
|
||||
Params p = m.processArgs(args);
|
||||
m.process(p);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Grabs command-line arguments.
|
||||
* The expected arguments are:
|
||||
* <ul>
|
||||
* <li> The filename of the input Jar.
|
||||
* <li> The filename of the output Jar.
|
||||
* <li> One or more include/exclude patterns or files containing these patterns.
|
||||
* See {@link #addString(Params, String)} for syntax.
|
||||
* </ul>
|
||||
* @throws IOException on failure to read a pattern file.
|
||||
*/
|
||||
private Params processArgs(String[] args) throws IOException {
|
||||
Params p = new Params();
|
||||
|
||||
for (String arg : args) {
|
||||
if (arg.startsWith("--")) {
|
||||
if (arg.startsWith("--v")) {
|
||||
p.setVerbose();
|
||||
} else if (arg.startsWith("--s")) {
|
||||
p.setDumpSource();
|
||||
} else if (arg.startsWith("--h")) {
|
||||
usage(null);
|
||||
} else {
|
||||
usage("Unknown argument: " + arg);
|
||||
}
|
||||
} else if (p.getInputJarPath() == null) {
|
||||
p.setInputJarPath(arg);
|
||||
} else if (p.getOutputJarPath() == null) {
|
||||
p.setOutputJarPath(arg);
|
||||
} else {
|
||||
addString(p, arg);
|
||||
}
|
||||
}
|
||||
|
||||
if (p.getInputJarPath() == null && p.getOutputJarPath() == null) {
|
||||
usage("Missing input or output JAR.");
|
||||
}
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds one pattern string to the current filter.
|
||||
* The syntax must be:
|
||||
* <ul>
|
||||
* <li> +full_include or +prefix_include*
|
||||
* <li> -full_exclude or -prefix_exclude*
|
||||
* <li> @filename
|
||||
* </ul>
|
||||
* The input string is trimmed so any space around the first letter (-/+/@) or
|
||||
* at the end is removed. Empty strings are ignored.
|
||||
*
|
||||
* @param p The params which filters to edit.
|
||||
* @param s The string to examine.
|
||||
* @throws IOException
|
||||
*/
|
||||
private void addString(Params p, String s) throws IOException {
|
||||
if (s == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
s = s.trim();
|
||||
|
||||
if (s.length() < 2) {
|
||||
return;
|
||||
}
|
||||
|
||||
char mode = s.charAt(0);
|
||||
s = s.substring(1).trim();
|
||||
|
||||
if (mode == '@') {
|
||||
addStringsFromFile(p, s);
|
||||
|
||||
} else if (mode == '-') {
|
||||
s = s.replace('.', '/'); // transform FQCN into ASM internal name
|
||||
if (s.endsWith("*")) {
|
||||
p.getFilter().getExcludePrefix().add(s.substring(0, s.length() - 1));
|
||||
} else {
|
||||
p.getFilter().getExcludeFull().add(s);
|
||||
}
|
||||
|
||||
} else if (mode == '+') {
|
||||
s = s.replace('.', '/'); // transform FQCN into ASM internal name
|
||||
if (s.endsWith("*")) {
|
||||
p.getFilter().getIncludePrefix().add(s.substring(0, s.length() - 1));
|
||||
} else {
|
||||
p.getFilter().getIncludeFull().add(s);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds all the filter strings from the given file.
|
||||
*
|
||||
* @param p The params which filter to edit.
|
||||
* @param osFilePath The OS path to the file containing the patterns.
|
||||
* @throws IOException
|
||||
*
|
||||
* @see #addString(Params, String)
|
||||
*/
|
||||
private void addStringsFromFile(Params p, String osFilePath)
|
||||
throws IOException {
|
||||
BufferedReader br = null;
|
||||
try {
|
||||
br = new BufferedReader(new FileReader(osFilePath));
|
||||
String line;
|
||||
while ((line = br.readLine()) != null) {
|
||||
addString(p, line);
|
||||
}
|
||||
} finally {
|
||||
if (br != null) {
|
||||
br.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints some help to stdout.
|
||||
* @param error The error that generated the usage, if any. Can be null.
|
||||
*/
|
||||
private void usage(String error) {
|
||||
if (error != null) {
|
||||
System.out.println("ERROR: " + error);
|
||||
}
|
||||
|
||||
System.out.println("Usage: mkstub [--h|--s|--v] input.jar output.jar [excluded-class @excluded-classes-file ...]");
|
||||
|
||||
System.out.println("Options:\n" +
|
||||
" --h | --help : print this usage.\n" +
|
||||
" --v | --verbose : verbose mode.\n" +
|
||||
" --s | --source : dump source equivalent to modified byte code.\n\n");
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs the main workflow of this app:
|
||||
* <ul>
|
||||
* <li> Read the input Jar to get all its classes.
|
||||
* <li> Filter out all classes that should not be included or that should be excluded.
|
||||
* <li> Goes thru the classes, filters methods/fields and generate their source
|
||||
* in a directory called "<outpath_jar_path>_sources"
|
||||
* <li> Does the same filtering on the classes but this time generates the real stubbed
|
||||
* output jar.
|
||||
* </ul>
|
||||
*/
|
||||
private void process(Params p) throws IOException {
|
||||
AsmAnalyzer aa = new AsmAnalyzer();
|
||||
Map<String, ClassReader> classes = aa.parseInputJar(p.getInputJarPath());
|
||||
|
||||
Logger log = new Logger(p.isVerbose());
|
||||
log.info("Classes loaded: %d", classes.size());
|
||||
|
||||
aa.filter(classes, p.getFilter(), log);
|
||||
log.info("Classes filtered: %d", classes.size());
|
||||
|
||||
// dump as Java source files, mostly for debugging
|
||||
if (p.isDumpSource()) {
|
||||
SourceGenerator src_gen = new SourceGenerator(log);
|
||||
File dst_src_dir = new File(p.getOutputJarPath() + "_sources");
|
||||
dst_src_dir.mkdir();
|
||||
src_gen.generateSource(dst_src_dir, classes, p.getFilter());
|
||||
}
|
||||
|
||||
// dump the stubbed jar
|
||||
StubGenerator stub_gen = new StubGenerator(log);
|
||||
File dst_jar = new File(p.getOutputJarPath());
|
||||
stub_gen.generateStubbedJar(dst_jar, classes, p.getFilter());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,96 @@
|
|||
/*
|
||||
* 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.Main.Logger;
|
||||
import com.android.mkstubs.sourcer.ClassSourcer;
|
||||
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.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
/**
|
||||
* Given a set of already filtered classes, this filters out all private members and then
|
||||
* generates the Java source for the remaining classes.
|
||||
* <p/>
|
||||
* This is an helper extracted for convenience. Callers just need to use
|
||||
* {@link #generateSource(File, Map, Filter)}.
|
||||
*/
|
||||
class SourceGenerator {
|
||||
|
||||
private Logger mLog;
|
||||
|
||||
public SourceGenerator(Logger log) {
|
||||
mLog = log;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate source for the stubbed classes, mostly for debug purposes.
|
||||
* @throws IOException
|
||||
*/
|
||||
public void generateSource(File baseDir,
|
||||
Map<String, ClassReader> classes,
|
||||
Filter filter) throws IOException {
|
||||
|
||||
for (Entry<String, ClassReader> entry : classes.entrySet()) {
|
||||
ClassReader cr = entry.getValue();
|
||||
|
||||
String name = classNameToJavaPath(cr.getClassName());
|
||||
|
||||
try (FileWriter fw = createWriter(baseDir, name)) {
|
||||
visitClassSource(fw, cr, filter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FileWriter createWriter(File baseDir, String name) throws IOException {
|
||||
File f = new File(baseDir, name);
|
||||
f.getParentFile().mkdirs();
|
||||
|
||||
mLog.debug("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 visitClassSource(Writer fw, ClassReader cr, Filter filter) {
|
||||
mLog.debug("Dump " + cr.getClassName());
|
||||
|
||||
ClassVisitor javaWriter = new ClassSourcer(new Output(fw));
|
||||
ClassVisitor classFilter = new FilterClassAdapter(javaWriter, filter, mLog);
|
||||
cr.accept(classFilter, 0 /*flags*/);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,113 @@
|
|||
/*
|
||||
* 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.Main.Logger;
|
||||
import com.android.mkstubs.stubber.ClassStubber;
|
||||
|
||||
import org.objectweb.asm.ClassReader;
|
||||
import org.objectweb.asm.ClassVisitor;
|
||||
import org.objectweb.asm.ClassWriter;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.TreeMap;
|
||||
import java.util.jar.JarEntry;
|
||||
import java.util.jar.JarOutputStream;
|
||||
|
||||
/**
|
||||
* Given a set of already filtered classes, this filters out all private members,
|
||||
* stubs the remaining classes and then generates a Jar out of them.
|
||||
* <p/>
|
||||
* This is an helper extracted for convenience. Callers just need to use
|
||||
* {@link #generateStubbedJar(File, Map, Filter)}.
|
||||
*/
|
||||
class StubGenerator {
|
||||
|
||||
private Logger mLog;
|
||||
|
||||
public StubGenerator(Logger log) {
|
||||
mLog = log;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate source for the stubbed classes, mostly for debug purposes.
|
||||
* @throws IOException
|
||||
*/
|
||||
public void generateStubbedJar(File destJar,
|
||||
Map<String, ClassReader> classes,
|
||||
Filter filter) throws IOException {
|
||||
|
||||
TreeMap<String, byte[]> all = new TreeMap<>();
|
||||
|
||||
for (Entry<String, ClassReader> entry : classes.entrySet()) {
|
||||
ClassReader cr = entry.getValue();
|
||||
|
||||
byte[] b = visitClassStubber(cr, filter);
|
||||
String name = classNameToEntryPath(cr.getClassName());
|
||||
all.put(name, b);
|
||||
}
|
||||
|
||||
createJar(new FileOutputStream(destJar), all);
|
||||
|
||||
mLog.debug("Wrote %s", destJar.getPath());
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.class"
|
||||
*/
|
||||
String classNameToEntryPath(String className) {
|
||||
return className.replaceAll("\\.", "/").concat(".class");
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the JAR file.
|
||||
*
|
||||
* @param outStream The file output stream were to write the JAR.
|
||||
* @param all The map of all classes to output.
|
||||
* @throws IOException if an I/O error has occurred
|
||||
*/
|
||||
void createJar(FileOutputStream outStream, Map<String,byte[]> all) throws IOException {
|
||||
JarOutputStream jar = new JarOutputStream(outStream);
|
||||
for (Entry<String, byte[]> entry : all.entrySet()) {
|
||||
String name = entry.getKey();
|
||||
JarEntry jar_entry = new JarEntry(name);
|
||||
jar.putNextEntry(jar_entry);
|
||||
jar.write(entry.getValue());
|
||||
jar.closeEntry();
|
||||
}
|
||||
jar.flush();
|
||||
jar.close();
|
||||
}
|
||||
|
||||
byte[] visitClassStubber(ClassReader cr, Filter filter) {
|
||||
mLog.debug("Stub " + cr.getClassName());
|
||||
|
||||
// Rewrite the new class from scratch, without reusing the constant pool from the
|
||||
// original class reader.
|
||||
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
|
||||
|
||||
ClassVisitor stubWriter = new ClassStubber(cw);
|
||||
ClassVisitor classFilter = new FilterClassAdapter(stubWriter, filter, mLog);
|
||||
cr.accept(classFilter, 0 /*flags*/);
|
||||
return cw.toByteArray();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,111 @@
|
|||
/*
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* Source generator for the access fields of methods, fields and classes.
|
||||
* <p/>
|
||||
* Given an integer access field and a type ({@link #IS_CLASS}, {@link #IS_FIELD} or
|
||||
* {@link #IS_METHOD}), the {@link #write(int, int)} method can generate a string
|
||||
* desribing the access modifiers for a Java source.
|
||||
*/
|
||||
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;
|
||||
|
||||
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".
|
||||
* <p/>
|
||||
* It is up to the caller to filter extra keywords that should not be generated,
|
||||
* e.g. {@link Flag#ACC_SYNTHETIC}.
|
||||
*
|
||||
* @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,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.sourcer;
|
||||
|
||||
import com.android.mkstubs.Main;
|
||||
|
||||
import org.objectweb.asm.AnnotationVisitor;
|
||||
|
||||
/**
|
||||
* An annotation visitor that generates Java source for an annotation.
|
||||
*/
|
||||
class AnnotationSourcer extends 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) {
|
||||
super(Main.ASM_VERSION);
|
||||
mOutput = output;
|
||||
mOpenChar = isArray ? "[" : "(";
|
||||
mCloseChar = isArray ? "]" : ")";
|
||||
}
|
||||
|
||||
@Override
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitEnd() {
|
||||
if (mNeedClose) {
|
||||
mOutput.write(mCloseChar);
|
||||
}
|
||||
mOutput.write("\n");
|
||||
}
|
||||
|
||||
@Override
|
||||
public AnnotationVisitor visitAnnotation(String name, String desc) {
|
||||
startOpen();
|
||||
|
||||
mOutput.write("@%s", name);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AnnotationVisitor visitArray(String name) {
|
||||
startOpen();
|
||||
return new AnnotationSourcer(mOutput, true /*isArray*/);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitEnum(String name, String desc, String value) {
|
||||
mOutput.write("/* annotation enum not supported: %s */\n", name);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,151 @@
|
|||
/*
|
||||
* 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 com.android.mkstubs.Main;
|
||||
|
||||
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 writes a java source.
|
||||
*/
|
||||
public class ClassSourcer extends ClassVisitor {
|
||||
|
||||
private final Output mOutput;
|
||||
private final AccessSourcer mAccessSourcer;
|
||||
private String mClassName;
|
||||
|
||||
public ClassSourcer(Output output) {
|
||||
super(Main.ASM_VERSION);
|
||||
mOutput = output;
|
||||
mAccessSourcer = new AccessSourcer(mOutput);
|
||||
}
|
||||
|
||||
/* Examples:
|
||||
* name = com/foo/MyClass
|
||||
* signature = null (if not generic)
|
||||
* superName = java/lang/Object
|
||||
* interfaces = [ java/lang/Runnable ... ]
|
||||
*/
|
||||
@Override
|
||||
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");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitEnd() {
|
||||
mOutput.write("}\n");
|
||||
}
|
||||
|
||||
@Override
|
||||
public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
|
||||
mOutput.write("@%s", desc);
|
||||
return new AnnotationSourcer(mOutput);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitAttribute(Attribute attr) {
|
||||
mOutput.write("%s /* non-standard class attribute */ ", attr.type);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
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);
|
||||
}
|
||||
|
||||
@Override
|
||||
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);
|
||||
}
|
||||
|
||||
@Override
|
||||
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.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitOuterClass(String owner, String name, String desc) {
|
||||
// Skip outer classes.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitSource(String source, String debug) {
|
||||
// Skip source information.
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,80 @@
|
|||
/*
|
||||
* 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 com.android.mkstubs.Main;
|
||||
|
||||
import org.objectweb.asm.AnnotationVisitor;
|
||||
import org.objectweb.asm.Attribute;
|
||||
import org.objectweb.asm.FieldVisitor;
|
||||
import org.objectweb.asm.Type;
|
||||
import org.objectweb.asm.signature.SignatureReader;
|
||||
|
||||
/**
|
||||
* A field visitor that generates Java source defining a field.
|
||||
*/
|
||||
class FieldSourcer extends 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) {
|
||||
super(Main.ASM_VERSION);
|
||||
mOutput = output;
|
||||
mAccess = access;
|
||||
mName = name;
|
||||
mDesc = desc;
|
||||
mSignature = signature;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
|
||||
mOutput.write("@%s", desc);
|
||||
return new AnnotationSourcer(mOutput);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitAttribute(Attribute attr) {
|
||||
mOutput.write("%s /* non-standard attribute */ ", attr.type);
|
||||
}
|
||||
|
||||
@Override
|
||||
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", Type.getType(mDesc).getClassName());
|
||||
} 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");
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,262 @@
|
|||
/*
|
||||
* 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 com.android.mkstubs.Main;
|
||||
|
||||
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 extends 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) {
|
||||
super(Main.ASM_VERSION);
|
||||
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;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitCode() {
|
||||
writeHeader();
|
||||
|
||||
// write the stub itself
|
||||
mOutput.write("throw new RuntimeException(\"Stub\");");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitEnd() {
|
||||
writeHeader();
|
||||
mOutput.write("\n}\n");
|
||||
}
|
||||
|
||||
@Override
|
||||
public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
|
||||
mOutput.write("@%s", desc);
|
||||
return new AnnotationSourcer(mOutput);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AnnotationVisitor visitAnnotationDefault() {
|
||||
// pass
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitAttribute(Attribute attr) {
|
||||
mOutput.write("%s /* non-standard method attribute */ ", attr.type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitFieldInsn(int opcode, String owner, String name, String desc) {
|
||||
// pass
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitFrame(int type, int local, Object[] local2, int stack, Object[] stack2) {
|
||||
// pass
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitIincInsn(int var, int increment) {
|
||||
// pass
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitInsn(int opcode) {
|
||||
// pass
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitIntInsn(int opcode, int operand) {
|
||||
// pass
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitJumpInsn(int opcode, Label label) {
|
||||
// pass
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitLabel(Label label) {
|
||||
// pass
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitLdcInsn(Object cst) {
|
||||
// pass
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitLineNumber(int line, Label start) {
|
||||
// pass
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitLocalVariable(String name, String desc, String signature,
|
||||
Label start, Label end, int index) {
|
||||
// pass
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitLookupSwitchInsn(Label dflt, int[] keys, Label[] labels) {
|
||||
// pass
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitMaxs(int maxStack, int maxLocals) {
|
||||
// pass
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean itf) {
|
||||
// pass
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitMultiANewArrayInsn(String desc, int dims) {
|
||||
// pass
|
||||
}
|
||||
|
||||
@Override
|
||||
public AnnotationVisitor visitParameterAnnotation(int parameter, String desc, boolean visible) {
|
||||
// pass
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitTableSwitchInsn(int min, int max, Label dflt, Label[] labels) {
|
||||
// pass
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitTryCatchBlock(Label start, Label end, Label handler, String type) {
|
||||
// pass
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitTypeInsn(int opcode, String type) {
|
||||
// pass
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitVarInsn(int opcode, int var) {
|
||||
// pass
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,76 @@
|
|||
/*
|
||||
* 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 java.io.IOException;
|
||||
import java.io.Writer;
|
||||
|
||||
/**
|
||||
* An {@link Output} objects is an helper to write to a character stream {@link Writer}.
|
||||
* <p/>
|
||||
* It provide some helper methods to the various "sourcer" classes from this package
|
||||
* to help them write to the underlying stream.
|
||||
*/
|
||||
public class Output {
|
||||
|
||||
private final Writer mWriter;
|
||||
|
||||
/**
|
||||
* Creates a new {@link Output} object that wraps the given {@link Writer}.
|
||||
* <p/>
|
||||
* The caller is responsible of opening and closing the {@link Writer}.
|
||||
*
|
||||
* @param writer The writer to write to. Could be a file, a string, etc.
|
||||
*/
|
||||
public Output(Writer writer) {
|
||||
mWriter = writer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a formatted string to the writer.
|
||||
*
|
||||
* @param format The format string.
|
||||
* @param args The arguments for the format string.
|
||||
*
|
||||
* @see String#format(String, Object...)
|
||||
*/
|
||||
public void write(String format, Object... args) {
|
||||
try {
|
||||
mWriter.write(String.format(format, args));
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a single character to the writer.
|
||||
*
|
||||
* @param c The character to write.
|
||||
*/
|
||||
public void write(char c) {
|
||||
write(Character.toString(c));
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a {@link StringBuilder} to the writer.
|
||||
*
|
||||
* @param sb The {@link StringBuilder#toString()} method is used to ge the string to write.
|
||||
*/
|
||||
public void write(StringBuilder sb) {
|
||||
write(sb.toString());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,307 @@
|
|||
/*
|
||||
* 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 com.android.mkstubs.Main;
|
||||
|
||||
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;
|
||||
|
||||
/**
|
||||
* A signature visitor that can be used to generate Java source corresponding to
|
||||
* various types of signatures.
|
||||
* <p/>
|
||||
* Terminology: a "signature" is a type descriptor for generics. There are different types
|
||||
* of signatures depending on the context where they are used, e.g. method declarations,
|
||||
* method parameters, class declarations, etc..
|
||||
* <p/>
|
||||
* 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. the signature is written as "(parameters)return-type" where we want to generate
|
||||
* "return-type method-name (parameters)". To handle this case, the return-type and parameters
|
||||
* are <em>not</em> output directly but are instead accumulated in internal variables that you can
|
||||
* get later using {@link #getReturnType()}, {@link #getParameters()}, {@link #getSuperClass()}
|
||||
* and {@link #formalsToString()}.
|
||||
*/
|
||||
class SignatureSourcer extends 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;
|
||||
|
||||
/**
|
||||
* {@link SignatureSourcer} generated when parsing the return type of <em>this</em>
|
||||
* signature. Initially null.
|
||||
*/
|
||||
private SignatureSourcer mReturnType;
|
||||
|
||||
/**
|
||||
* {@link SignatureSourcer} generated when parsing the super class of <em>this</em>
|
||||
* signature. Initially null.
|
||||
*/
|
||||
private SignatureSourcer mSuperClass;
|
||||
|
||||
/**
|
||||
* {@link SignatureSourcer}s for each parameters generated when parsing the method parameters
|
||||
* of <em>this</em> signature. Initially empty but not null.
|
||||
*/
|
||||
private ArrayList<SignatureSourcer> mParameters = new ArrayList<>();
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Constructs a new {@link SignatureWriter} object.
|
||||
*/
|
||||
public SignatureSourcer() {
|
||||
super(Main.ASM_VERSION);
|
||||
}
|
||||
|
||||
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
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
@Override
|
||||
public void visitFormalTypeParameter(final String name) {
|
||||
if (!mWritingFormals) {
|
||||
mWritingFormals = true;
|
||||
getBuf().append('<');
|
||||
} else {
|
||||
getBuf().append(", ");
|
||||
}
|
||||
getBuf().append(name);
|
||||
getBuf().append(" extends ");
|
||||
}
|
||||
|
||||
@Override
|
||||
public SignatureVisitor visitClassBound() {
|
||||
// we don't differentiate between visiting a sub class or interface type
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SignatureVisitor visitInterfaceBound() {
|
||||
// we don't differentiate between visiting a sub class or interface type
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SignatureVisitor visitSuperclass() {
|
||||
endFormals();
|
||||
SignatureSourcer sourcer = new SignatureSourcer();
|
||||
assert mSuperClass == null;
|
||||
mSuperClass = sourcer;
|
||||
return sourcer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SignatureVisitor visitInterface() {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SignatureVisitor visitParameterType() {
|
||||
endFormals();
|
||||
SignatureSourcer sourcer = new SignatureSourcer();
|
||||
mParameters.add(sourcer);
|
||||
return sourcer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SignatureVisitor visitReturnType() {
|
||||
endFormals();
|
||||
SignatureSourcer sourcer = new SignatureSourcer();
|
||||
assert mReturnType == null;
|
||||
mReturnType = sourcer;
|
||||
return sourcer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SignatureVisitor visitExceptionType() {
|
||||
getBuf().append('^');
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitBaseType(final char descriptor) {
|
||||
getBuf().append(Type.getType(Character.toString(descriptor)).getClassName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitTypeVariable(final String name) {
|
||||
getBuf().append(name.replace('/', '.'));
|
||||
}
|
||||
|
||||
@Override
|
||||
public SignatureVisitor visitArrayType() {
|
||||
getBuf().append('[');
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitClassType(final String name) {
|
||||
getBuf().append(name.replace('/', '.'));
|
||||
mArgumentStack *= 2;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitInnerClassType(final String name) {
|
||||
endArguments();
|
||||
getBuf().append('.');
|
||||
getBuf().append(name.replace('/', '.'));
|
||||
mArgumentStack *= 2;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitTypeArgument() {
|
||||
if (mArgumentStack % 2 == 0) {
|
||||
++mArgumentStack;
|
||||
getBuf().append('<');
|
||||
} else {
|
||||
getBuf().append(", ");
|
||||
}
|
||||
getBuf().append('*');
|
||||
}
|
||||
|
||||
@Override
|
||||
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;
|
||||
}
|
||||
|
||||
@Override
|
||||
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,88 @@
|
|||
/*
|
||||
* 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.stubber;
|
||||
|
||||
import com.android.mkstubs.Main;
|
||||
|
||||
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;
|
||||
|
||||
/**
|
||||
* A class visitor that generates stubs for all methods of the visited class.
|
||||
* Everything else is passed as-is.
|
||||
*/
|
||||
public class ClassStubber extends ClassVisitor {
|
||||
|
||||
public ClassStubber(ClassVisitor cv) {
|
||||
super(Main.ASM_VERSION, cv);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(int version, int access,
|
||||
String name,
|
||||
String signature,
|
||||
String superName,
|
||||
String[] interfaces) {
|
||||
super.visit(version, access, name, signature, superName, interfaces);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitEnd() {
|
||||
super.visitEnd();
|
||||
}
|
||||
|
||||
@Override
|
||||
public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
|
||||
return super.visitAnnotation(desc, visible);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitAttribute(Attribute attr) {
|
||||
super.visitAttribute(attr);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MethodVisitor visitMethod(int access, String name, String desc, String signature,
|
||||
String[] exceptions) {
|
||||
MethodVisitor mw = super.visitMethod(access, name, desc, signature, exceptions);
|
||||
return new MethodStubber(mw, access, name, desc, signature, exceptions);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FieldVisitor visitField(int access, String name, String desc, String signature,
|
||||
Object value) {
|
||||
return super.visitField(access, name, desc, signature, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitInnerClass(String name, String outerName, String innerName, int access) {
|
||||
super.visitInnerClass(name, outerName, innerName, access);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitOuterClass(String owner, String name, String desc) {
|
||||
super.visitOuterClass(owner, name, desc);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitSource(String source, String debug) {
|
||||
super.visitSource(source, debug);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,187 @@
|
|||
/*
|
||||
* 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.stubber;
|
||||
|
||||
import com.android.mkstubs.Main;
|
||||
|
||||
import org.objectweb.asm.AnnotationVisitor;
|
||||
import org.objectweb.asm.Attribute;
|
||||
import org.objectweb.asm.Label;
|
||||
import org.objectweb.asm.MethodVisitor;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
|
||||
/**
|
||||
* A method visitor that generates a code stub for the visited method.
|
||||
* <p/>
|
||||
* Annotations and parameters are passed as-is.
|
||||
* All other code is replaced by the following:
|
||||
* <pre>throw new RuntimeException("stub");</pre>
|
||||
* Note that constructors rewritten this way will probably fail with the runtime bytecode
|
||||
* verifier since no call to <code>super</code> is generated.
|
||||
*/
|
||||
public class MethodStubber extends MethodVisitor {
|
||||
|
||||
public MethodStubber(MethodVisitor mw,
|
||||
int access, String name, String desc, String signature, String[] exceptions) {
|
||||
super(Main.ASM_VERSION, mw);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitCode() {
|
||||
Label l0 = new Label();
|
||||
mv.visitLabel(l0);
|
||||
mv.visitLineNumber(36, l0);
|
||||
mv.visitTypeInsn(Opcodes.NEW, "java/lang/RuntimeException");
|
||||
mv.visitInsn(Opcodes.DUP);
|
||||
mv.visitLdcInsn("stub");
|
||||
mv.visitMethodInsn(
|
||||
Opcodes.INVOKESPECIAL, // opcode
|
||||
"java/lang/RuntimeException", // owner
|
||||
"<init>", // name
|
||||
"(Ljava/lang/String;)V", // desc
|
||||
false);
|
||||
mv.visitInsn(Opcodes.ATHROW);
|
||||
Label l1 = new Label();
|
||||
mv.visitLabel(l1);
|
||||
mv.visitLocalVariable(
|
||||
"this", // name
|
||||
"Lcom/android/mkstubs/stubber/MethodStubber;", // desc
|
||||
null, // signature
|
||||
l0, // label start
|
||||
l1, // label end
|
||||
0); // index
|
||||
mv.visitMaxs(3, 1); // maxStack, maxLocals
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitEnd() {
|
||||
super.visitEnd();
|
||||
}
|
||||
|
||||
@Override
|
||||
public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
|
||||
return super.visitAnnotation(desc, visible);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AnnotationVisitor visitAnnotationDefault() {
|
||||
return super.visitAnnotationDefault();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitAttribute(Attribute attr) {
|
||||
super.visitAttribute(attr);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AnnotationVisitor visitParameterAnnotation(int parameter, String desc, boolean visible) {
|
||||
return super.visitParameterAnnotation(parameter, desc, visible);
|
||||
}
|
||||
|
||||
// -- stuff that gets skipped
|
||||
|
||||
@Override
|
||||
public void visitFieldInsn(int opcode, String owner, String name, String desc) {
|
||||
// skip
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitFrame(int type, int local, Object[] local2, int stack, Object[] stack2) {
|
||||
// skip
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitIincInsn(int var, int increment) {
|
||||
// skip
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitInsn(int opcode) {
|
||||
// skip
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitIntInsn(int opcode, int operand) {
|
||||
// skip
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitJumpInsn(int opcode, Label label) {
|
||||
// skip
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitLabel(Label label) {
|
||||
// skip
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitLdcInsn(Object cst) {
|
||||
// skip
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitLineNumber(int line, Label start) {
|
||||
// skip
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitLocalVariable(String name, String desc, String signature,
|
||||
Label start, Label end, int index) {
|
||||
// skip
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitLookupSwitchInsn(Label dflt, int[] keys, Label[] labels) {
|
||||
// skip
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitMaxs(int maxStack, int maxLocals) {
|
||||
// skip
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean itf) {
|
||||
// skip
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitMultiANewArrayInsn(String desc, int dims) {
|
||||
// skip
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitTableSwitchInsn(int min, int max, Label dflt, Label[] labels) {
|
||||
// skip
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitTryCatchBlock(Label start, Label end, Label handler, String type) {
|
||||
// skip
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitTypeInsn(int opcode, String type) {
|
||||
// skip
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitVarInsn(int opcode, int var) {
|
||||
// skip
|
||||
}
|
||||
}
|
|
@ -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,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;
|
||||
|
||||
|
||||
import com.android.mkstubs.Main.Logger;
|
||||
|
||||
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;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public class SourceGeneratorTest {
|
||||
|
||||
private SourceGenerator mGen;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
mGen = new SourceGenerator(new Logger(false));
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testDumpClass() throws Exception {
|
||||
StringWriter sw = new StringWriter();
|
||||
ClassReader cr = new ClassReader("data/TestBaseClass");
|
||||
|
||||
mGen.visitClassSource(sw, cr, new Filter());
|
||||
|
||||
String s = sw.toString();
|
||||
Assert.assertNotNull(s);
|
||||
}
|
||||
}
|
|
@ -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,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 ClassSourcerTest 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");
|
||||
|
||||
ClassSourcer jw = new ClassSourcer(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");
|
||||
|
||||
ClassSourcer jw = new ClassSourcer(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");
|
||||
|
||||
ClassSourcer jw = new ClassSourcer(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,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,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);
|
||||
}
|
||||
}
|
|
@ -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() {
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
|
@ -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) {
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue