summaryrefslogtreecommitdiff
path: root/tools
diff options
context:
space:
mode:
authorTor Norbye <tnorbye@google.com>2013-08-13 14:47:52 -0700
committerTor Norbye <tnorbye@google.com>2013-08-13 14:56:13 -0700
commit11835f7fcb47d44b1f70f154aec9a597e9541321 (patch)
tree3919cc4f9405243d994a8a14e1a750902a601c64 /tools
parentabb260a280af25500b2d5c95890c9af116981f4d (diff)
Add typedef removal tool
The rmtypedefs tool is inteded only for the Android build itself. It is given a set of .class file folders, and it finds any .class files within those folders that correspond to "typedef annotations": these are annotation classes that themselves have been annotated with @IntDef or @StringDef. These typedefs should all be using @Retention(RetentionPolicy.SOURCE), something this tool will check and report if not the case. However, even if an annotation only has source level retention, the annotation class *itself*, will still be created as a .class file. We don't want these annotations in the Android system image, so this tool is used to find and nuke the corresponding .class files for the annotations themselves. Change-Id: Ia343cc5bdbf215ded24b4354f3d92f5a9076eae3
Diffstat (limited to 'tools')
-rw-r--r--tools/rmtypedefs/.gitignore3
-rw-r--r--tools/rmtypedefs/.idea/compiler.xml23
-rw-r--r--tools/rmtypedefs/.idea/copyright/profiles_settings.xml5
-rw-r--r--tools/rmtypedefs/.idea/encodings.xml5
-rw-r--r--tools/rmtypedefs/.idea/misc.xml10
-rw-r--r--tools/rmtypedefs/.idea/modules.xml9
-rw-r--r--tools/rmtypedefs/.idea/scopes/scope_settings.xml5
-rw-r--r--tools/rmtypedefs/.idea/uiDesigner.xml125
-rw-r--r--tools/rmtypedefs/.idea/vcs.xml8
-rw-r--r--tools/rmtypedefs/Android.mk46
-rw-r--r--tools/rmtypedefs/README.txt13
-rw-r--r--tools/rmtypedefs/etc/manifest.txt2
-rwxr-xr-xtools/rmtypedefs/etc/rmtypedefs46
-rw-r--r--tools/rmtypedefs/rmtypedefs.iml36
-rw-r--r--tools/rmtypedefs/src/Android.mk31
-rw-r--r--tools/rmtypedefs/src/com/android/tools/rmtypedefs/RmTypeDefs.java224
16 files changed, 591 insertions, 0 deletions
diff --git a/tools/rmtypedefs/.gitignore b/tools/rmtypedefs/.gitignore
new file mode 100644
index 000000000..04d423fd6
--- /dev/null
+++ b/tools/rmtypedefs/.gitignore
@@ -0,0 +1,3 @@
+out
+.idea/workspace.xml
+.DS_Store
diff --git a/tools/rmtypedefs/.idea/compiler.xml b/tools/rmtypedefs/.idea/compiler.xml
new file mode 100644
index 000000000..217af471a
--- /dev/null
+++ b/tools/rmtypedefs/.idea/compiler.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+ <component name="CompilerConfiguration">
+ <option name="DEFAULT_COMPILER" value="Javac" />
+ <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" />
+ </wildcardResourcePatterns>
+ <annotationProcessing>
+ <profile default="true" name="Default" enabled="false">
+ <processorPath useClasspath="true" />
+ </profile>
+ </annotationProcessing>
+ </component>
+</project>
+
diff --git a/tools/rmtypedefs/.idea/copyright/profiles_settings.xml b/tools/rmtypedefs/.idea/copyright/profiles_settings.xml
new file mode 100644
index 000000000..3572571ad
--- /dev/null
+++ b/tools/rmtypedefs/.idea/copyright/profiles_settings.xml
@@ -0,0 +1,5 @@
+<component name="CopyrightManager">
+ <settings default="">
+ <module2copyright />
+ </settings>
+</component> \ No newline at end of file
diff --git a/tools/rmtypedefs/.idea/encodings.xml b/tools/rmtypedefs/.idea/encodings.xml
new file mode 100644
index 000000000..e206d70d8
--- /dev/null
+++ b/tools/rmtypedefs/.idea/encodings.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+ <component name="Encoding" useUTFGuessing="true" native2AsciiForPropertiesFiles="false" />
+</project>
+
diff --git a/tools/rmtypedefs/.idea/misc.xml b/tools/rmtypedefs/.idea/misc.xml
new file mode 100644
index 000000000..97320410e
--- /dev/null
+++ b/tools/rmtypedefs/.idea/misc.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+ <component name="EntryPointsManager">
+ <entry_points version="2.0" />
+ </component>
+ <component name="ProjectRootManager" version="2" languageLevel="JDK_1_6" assert-keyword="true" jdk-15="true" project-jdk-name="1.6" project-jdk-type="JavaSDK">
+ <output url="file://$PROJECT_DIR$/out" />
+ </component>
+</project>
+
diff --git a/tools/rmtypedefs/.idea/modules.xml b/tools/rmtypedefs/.idea/modules.xml
new file mode 100644
index 000000000..52f04c30f
--- /dev/null
+++ b/tools/rmtypedefs/.idea/modules.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+ <component name="ProjectModuleManager">
+ <modules>
+ <module fileurl="file://$PROJECT_DIR$/rmtypedefs.iml" filepath="$PROJECT_DIR$/rmtypedefs.iml" />
+ </modules>
+ </component>
+</project>
+
diff --git a/tools/rmtypedefs/.idea/scopes/scope_settings.xml b/tools/rmtypedefs/.idea/scopes/scope_settings.xml
new file mode 100644
index 000000000..922003b84
--- /dev/null
+++ b/tools/rmtypedefs/.idea/scopes/scope_settings.xml
@@ -0,0 +1,5 @@
+<component name="DependencyValidationManager">
+ <state>
+ <option name="SKIP_IMPORT_STATEMENTS" value="false" />
+ </state>
+</component> \ No newline at end of file
diff --git a/tools/rmtypedefs/.idea/uiDesigner.xml b/tools/rmtypedefs/.idea/uiDesigner.xml
new file mode 100644
index 000000000..3b0002030
--- /dev/null
+++ b/tools/rmtypedefs/.idea/uiDesigner.xml
@@ -0,0 +1,125 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+ <component name="Palette2">
+ <group name="Swing">
+ <item class="com.intellij.uiDesigner.HSpacer" tooltip-text="Horizontal Spacer" icon="/com/intellij/uiDesigner/icons/hspacer.png" removable="false" auto-create-binding="false" can-attach-label="false">
+ <default-constraints vsize-policy="1" hsize-policy="6" anchor="0" fill="1" />
+ </item>
+ <item class="com.intellij.uiDesigner.VSpacer" tooltip-text="Vertical Spacer" icon="/com/intellij/uiDesigner/icons/vspacer.png" removable="false" auto-create-binding="false" can-attach-label="false">
+ <default-constraints vsize-policy="6" hsize-policy="1" anchor="0" fill="2" />
+ </item>
+ <item class="javax.swing.JPanel" icon="/com/intellij/uiDesigner/icons/panel.png" removable="false" auto-create-binding="false" can-attach-label="false">
+ <default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3" />
+ </item>
+ <item class="javax.swing.JScrollPane" icon="/com/intellij/uiDesigner/icons/scrollPane.png" removable="false" auto-create-binding="false" can-attach-label="true">
+ <default-constraints vsize-policy="7" hsize-policy="7" anchor="0" fill="3" />
+ </item>
+ <item class="javax.swing.JButton" icon="/com/intellij/uiDesigner/icons/button.png" removable="false" auto-create-binding="true" can-attach-label="false">
+ <default-constraints vsize-policy="0" hsize-policy="3" anchor="0" fill="1" />
+ <initial-values>
+ <property name="text" value="Button" />
+ </initial-values>
+ </item>
+ <item class="javax.swing.JRadioButton" icon="/com/intellij/uiDesigner/icons/radioButton.png" removable="false" auto-create-binding="true" can-attach-label="false">
+ <default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
+ <initial-values>
+ <property name="text" value="RadioButton" />
+ </initial-values>
+ </item>
+ <item class="javax.swing.JCheckBox" icon="/com/intellij/uiDesigner/icons/checkBox.png" removable="false" auto-create-binding="true" can-attach-label="false">
+ <default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
+ <initial-values>
+ <property name="text" value="CheckBox" />
+ </initial-values>
+ </item>
+ <item class="javax.swing.JLabel" icon="/com/intellij/uiDesigner/icons/label.png" removable="false" auto-create-binding="false" can-attach-label="false">
+ <default-constraints vsize-policy="0" hsize-policy="0" anchor="8" fill="0" />
+ <initial-values>
+ <property name="text" value="Label" />
+ </initial-values>
+ </item>
+ <item class="javax.swing.JTextField" icon="/com/intellij/uiDesigner/icons/textField.png" removable="false" auto-create-binding="true" can-attach-label="true">
+ <default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
+ <preferred-size width="150" height="-1" />
+ </default-constraints>
+ </item>
+ <item class="javax.swing.JPasswordField" icon="/com/intellij/uiDesigner/icons/passwordField.png" removable="false" auto-create-binding="true" can-attach-label="true">
+ <default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
+ <preferred-size width="150" height="-1" />
+ </default-constraints>
+ </item>
+ <item class="javax.swing.JFormattedTextField" icon="/com/intellij/uiDesigner/icons/formattedTextField.png" removable="false" auto-create-binding="true" can-attach-label="true">
+ <default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
+ <preferred-size width="150" height="-1" />
+ </default-constraints>
+ </item>
+ <item class="javax.swing.JTextArea" icon="/com/intellij/uiDesigner/icons/textArea.png" removable="false" auto-create-binding="true" can-attach-label="true">
+ <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
+ <preferred-size width="150" height="50" />
+ </default-constraints>
+ </item>
+ <item class="javax.swing.JTextPane" icon="/com/intellij/uiDesigner/icons/textPane.png" removable="false" auto-create-binding="true" can-attach-label="true">
+ <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
+ <preferred-size width="150" height="50" />
+ </default-constraints>
+ </item>
+ <item class="javax.swing.JEditorPane" icon="/com/intellij/uiDesigner/icons/editorPane.png" removable="false" auto-create-binding="true" can-attach-label="true">
+ <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
+ <preferred-size width="150" height="50" />
+ </default-constraints>
+ </item>
+ <item class="javax.swing.JComboBox" icon="/com/intellij/uiDesigner/icons/comboBox.png" removable="false" auto-create-binding="true" can-attach-label="true">
+ <default-constraints vsize-policy="0" hsize-policy="2" anchor="8" fill="1" />
+ </item>
+ <item class="javax.swing.JTable" icon="/com/intellij/uiDesigner/icons/table.png" removable="false" auto-create-binding="true" can-attach-label="false">
+ <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
+ <preferred-size width="150" height="50" />
+ </default-constraints>
+ </item>
+ <item class="javax.swing.JList" icon="/com/intellij/uiDesigner/icons/list.png" removable="false" auto-create-binding="true" can-attach-label="false">
+ <default-constraints vsize-policy="6" hsize-policy="2" anchor="0" fill="3">
+ <preferred-size width="150" height="50" />
+ </default-constraints>
+ </item>
+ <item class="javax.swing.JTree" icon="/com/intellij/uiDesigner/icons/tree.png" removable="false" auto-create-binding="true" can-attach-label="false">
+ <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
+ <preferred-size width="150" height="50" />
+ </default-constraints>
+ </item>
+ <item class="javax.swing.JTabbedPane" icon="/com/intellij/uiDesigner/icons/tabbedPane.png" removable="false" auto-create-binding="true" can-attach-label="false">
+ <default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
+ <preferred-size width="200" height="200" />
+ </default-constraints>
+ </item>
+ <item class="javax.swing.JSplitPane" icon="/com/intellij/uiDesigner/icons/splitPane.png" removable="false" auto-create-binding="false" can-attach-label="false">
+ <default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
+ <preferred-size width="200" height="200" />
+ </default-constraints>
+ </item>
+ <item class="javax.swing.JSpinner" icon="/com/intellij/uiDesigner/icons/spinner.png" removable="false" auto-create-binding="true" can-attach-label="true">
+ <default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
+ </item>
+ <item class="javax.swing.JSlider" icon="/com/intellij/uiDesigner/icons/slider.png" removable="false" auto-create-binding="true" can-attach-label="false">
+ <default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
+ </item>
+ <item class="javax.swing.JSeparator" icon="/com/intellij/uiDesigner/icons/separator.png" removable="false" auto-create-binding="false" can-attach-label="false">
+ <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3" />
+ </item>
+ <item class="javax.swing.JProgressBar" icon="/com/intellij/uiDesigner/icons/progressbar.png" removable="false" auto-create-binding="true" can-attach-label="false">
+ <default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1" />
+ </item>
+ <item class="javax.swing.JToolBar" icon="/com/intellij/uiDesigner/icons/toolbar.png" removable="false" auto-create-binding="false" can-attach-label="false">
+ <default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1">
+ <preferred-size width="-1" height="20" />
+ </default-constraints>
+ </item>
+ <item class="javax.swing.JToolBar$Separator" icon="/com/intellij/uiDesigner/icons/toolbarSeparator.png" removable="false" auto-create-binding="false" can-attach-label="false">
+ <default-constraints vsize-policy="0" hsize-policy="0" anchor="0" fill="1" />
+ </item>
+ <item class="javax.swing.JScrollBar" icon="/com/intellij/uiDesigner/icons/scrollbar.png" removable="false" auto-create-binding="true" can-attach-label="false">
+ <default-constraints vsize-policy="6" hsize-policy="0" anchor="0" fill="2" />
+ </item>
+ </group>
+ </component>
+</project>
+
diff --git a/tools/rmtypedefs/.idea/vcs.xml b/tools/rmtypedefs/.idea/vcs.xml
new file mode 100644
index 000000000..a5dd08645
--- /dev/null
+++ b/tools/rmtypedefs/.idea/vcs.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+ <component name="VcsDirectoryMappings">
+ <mapping directory="" vcs="" />
+ <mapping directory="$PROJECT_DIR$/../.." vcs="Git" />
+ </component>
+</project>
+
diff --git a/tools/rmtypedefs/Android.mk b/tools/rmtypedefs/Android.mk
new file mode 100644
index 000000000..d79d2fffa
--- /dev/null
+++ b/tools/rmtypedefs/Android.mk
@@ -0,0 +1,46 @@
+# Copyright (C) 2013 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)
+
+# We use copy-file-to-new-target so that the installed
+# script file's timestamp is at least as new as the
+# .jar file it wraps.
+
+# the execution script
+# ============================================================
+include $(CLEAR_VARS)
+LOCAL_IS_HOST_MODULE := true
+LOCAL_MODULE_CLASS := EXECUTABLES
+LOCAL_MODULE := rmtypedefs
+
+#LOCAL_STATIC_JAVA_LIBRARIES := \
+# asm-tools \
+# guavalib
+
+include $(BUILD_SYSTEM)/base_rules.mk
+
+$(LOCAL_BUILT_MODULE): $(HOST_OUT_JAVA_LIBRARIES)/rmtypedefs$(COMMON_JAVA_PACKAGE_SUFFIX)
+$(LOCAL_BUILT_MODULE): $(LOCAL_PATH)/etc/rmtypedefs | $(ACP)
+ @echo "Copy: $(PRIVATE_MODULE) ($@)"
+ $(copy-file-to-new-target)
+ $(hide) chmod 755 $@
+
+# the other stuff
+# ============================================================
+subdirs := $(addprefix $(LOCAL_PATH)/,$(addsuffix /Android.mk, \
+ src \
+ ))
+
+include $(subdirs)
diff --git a/tools/rmtypedefs/README.txt b/tools/rmtypedefs/README.txt
new file mode 100644
index 000000000..9f3fb8b54
--- /dev/null
+++ b/tools/rmtypedefs/README.txt
@@ -0,0 +1,13 @@
+Android TypeDef Remover 1.0
+
+This utility finds and removes all .class files that have been
+annotated with the @IntDef annotation (android.annotations.IntDef) or
+the @StringDef annotation (android.annotations.StringDef).
+
+It also makes sure that these annotations have source level retention
+(@Retention(RetentionPolicy.SOURCE)), since otherwise uses of the
+typedef will appear in .class files as well.
+
+This is intended to be used during the build to strip out any typedef
+annotation classes, since these are not needed (or desirable) in the
+system image.
diff --git a/tools/rmtypedefs/etc/manifest.txt b/tools/rmtypedefs/etc/manifest.txt
new file mode 100644
index 000000000..39f2e29f7
--- /dev/null
+++ b/tools/rmtypedefs/etc/manifest.txt
@@ -0,0 +1,2 @@
+Manifest-Version: 1.0
+Main-Class: com.android.tools.rmtypedefs.RmTypeDefs
diff --git a/tools/rmtypedefs/etc/rmtypedefs b/tools/rmtypedefs/etc/rmtypedefs
new file mode 100755
index 000000000..bc0cbe22e
--- /dev/null
+++ b/tools/rmtypedefs/etc/rmtypedefs
@@ -0,0 +1,46 @@
+#!/bin/bash
+#
+# Copyright (C) 2013 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.
+
+# Set up prog to be the path of this script, including following symlinks,
+# and set up progdir to be the fully-qualified pathname of its directory.
+prog="$0"
+while [ -h "${prog}" ]; do
+ newProg=`/bin/ls -ld "${prog}"`
+ newProg=`expr "${newProg}" : ".* -> \(.*\)$"`
+ if expr "x${newProg}" : 'x/' >/dev/null; then
+ prog="${newProg}"
+ else
+ progdir=`dirname "${prog}"`
+ prog="${progdir}/${newProg}"
+ fi
+done
+oldwd=`pwd`
+progdir=`dirname "${prog}"`
+cd "${progdir}"
+progdir=`pwd`
+prog="${progdir}"/`basename "${prog}"`
+cd "${oldwd}"
+
+libdir=`dirname $progdir`/framework
+
+javaOpts=""
+while expr "x$1" : 'x-J' >/dev/null; do
+ opt=`expr "$1" : '-J\(.*\)'`
+ javaOpts="${javaOpts} -${opt}"
+ shift
+done
+
+exec java $javaOpts -jar $libdir/rmtypedefs.jar "$@"
diff --git a/tools/rmtypedefs/rmtypedefs.iml b/tools/rmtypedefs/rmtypedefs.iml
new file mode 100644
index 000000000..6e0f0fcff
--- /dev/null
+++ b/tools/rmtypedefs/rmtypedefs.iml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<module type="JAVA_MODULE" version="4">
+ <component name="NewModuleRootManager" inherit-compiler-output="false">
+ <output url="file://$MODULE_DIR$/../../../out/rmtypedefs" />
+ <output-test url="file://$MODULE_DIR$/../../../out/rmtypedefs" />
+ <exclude-output />
+ <content url="file://$MODULE_DIR$">
+ <sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
+ </content>
+ <orderEntry type="inheritedJdk" />
+ <orderEntry type="sourceFolder" forTests="false" />
+ <orderEntry type="module-library">
+ <library>
+ <CLASSES>
+ <root url="jar://$MODULE_DIR$/../../../prebuilts/tools/common/asm-tools/asm-4.0.jar!/" />
+ </CLASSES>
+ <JAVADOC />
+ <SOURCES>
+ <root url="jar://$MODULE_DIR$/../../../prebuilts/tools/common/asm-tools/src-4.0.zip!/" />
+ </SOURCES>
+ </library>
+ </orderEntry>
+ <orderEntry type="module-library">
+ <library>
+ <CLASSES>
+ <root url="jar://$MODULE_DIR$/../../../prebuilts/tools/common/guava-tools/guava-13.0.1.jar!/" />
+ </CLASSES>
+ <JAVADOC />
+ <SOURCES>
+ <root url="jar://$MODULE_DIR$/../../../prebuilts/tools/common/guava-tools/src.zip!/" />
+ </SOURCES>
+ </library>
+ </orderEntry>
+ </component>
+</module>
+
diff --git a/tools/rmtypedefs/src/Android.mk b/tools/rmtypedefs/src/Android.mk
new file mode 100644
index 000000000..067a2e655
--- /dev/null
+++ b/tools/rmtypedefs/src/Android.mk
@@ -0,0 +1,31 @@
+# Copyright (C) 2013 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)
+
+
+# rmtypedefs java library
+# ============================================================
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+LOCAL_JAR_MANIFEST := ../etc/manifest.txt
+LOCAL_STATIC_JAVA_LIBRARIES := \
+ asm-tools \
+ guava-tools
+
+LOCAL_MODULE:= rmtypedefs
+
+include $(BUILD_HOST_JAVA_LIBRARY)
+
diff --git a/tools/rmtypedefs/src/com/android/tools/rmtypedefs/RmTypeDefs.java b/tools/rmtypedefs/src/com/android/tools/rmtypedefs/RmTypeDefs.java
new file mode 100644
index 000000000..937559036
--- /dev/null
+++ b/tools/rmtypedefs/src/com/android/tools/rmtypedefs/RmTypeDefs.java
@@ -0,0 +1,224 @@
+/*
+ * Copyright (C) 2013 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.tools.rmtypedefs;
+
+import com.google.common.io.Files;
+
+import org.objectweb.asm.AnnotationVisitor;
+import org.objectweb.asm.ClassReader;
+import org.objectweb.asm.ClassVisitor;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.util.ArrayList;
+import java.util.List;
+
+import static org.objectweb.asm.Opcodes.ASM4;
+
+/**
+ * Finds and deletes typedef annotation classes (and also warns if their
+ * retention was wrong, such that uses embeds
+ */
+public class RmTypeDefs {
+
+ private static final String ANNOTATION = "java/lang/annotation/Annotation";
+ private static final String STRING_DEF = "android/annotation/StringDef";
+ private static final String INT_DEF = "android/annotation/IntDef";
+ private static final String INT_DEF_DESC = "L" + INT_DEF + ";";
+ private static final String STRING_DEF_DESC = "L" + STRING_DEF + ";";
+ private static final String RETENTION_DESC = "Ljava/lang/annotation/Retention;";
+ private static final String RETENTION_POLICY_DESC = "Ljava/lang/annotation/RetentionPolicy;";
+ private static final String SOURCE_RETENTION_VALUE = "SOURCE";
+
+ private boolean mQuiet;
+ private boolean mVerbose;
+ private boolean mHaveError;
+ private boolean mDryRun;
+
+ public static void main(String[] args) {
+ new RmTypeDefs().run(args);
+ }
+
+ private void run(String[] args) {
+ if (args.length == 0) {
+ usage(System.err);
+ System.exit(1);
+ }
+
+ List<File> dirs = new ArrayList<File>();
+ for (String arg : args) {
+ if (arg.equals("--help") || arg.equals("-h")) {
+ usage(System.out);
+ return;
+ } else if (arg.equals("-q") || arg.equals("--quiet") || arg.equals("--silent")) {
+ mQuiet = true;
+ } else if (arg.equals("-v") || arg.equals("--verbose")) {
+ mVerbose = true;
+ } else if (arg.equals("-n") || arg.equals("--dry-run")) {
+ mDryRun = true;
+ } else if (arg.startsWith("-")) {
+ System.err.println("Unknown argument " + arg);
+ usage(System.err);
+ System.exit(1);
+
+ } else {
+ // Other arguments should be file names
+ File file = new File(arg);
+ if (file.exists()) {
+ dirs.add(file);
+ } else {
+ System.err.println(file + " does not exist");
+ usage(System.err);
+ System.exit(1);
+ }
+ }
+ }
+
+ if (!mQuiet) {
+ System.out.println("Deleting @IntDef and @StringDef annotation class files");
+ }
+
+ for (File dir : dirs) {
+ find(dir);
+ }
+
+ System.exit(mHaveError ? -1 : 0);
+ }
+
+ private void find(File file) {
+ if (file.isDirectory()) {
+ File[] files = file.listFiles();
+ if (files != null) {
+ for (File f : files) {
+ find(f);
+ }
+ }
+ } else if (file.isFile()) {
+ String path = file.getPath();
+ if (path.endsWith(".class")) {
+ checkClass(file);
+ } else if (path.endsWith(".jar")) {
+ System.err.println(path + ": Warning: Encountered .jar file; .class files "
+ + "are not scanned and removed inside .jar files");
+ }
+ }
+ }
+
+ private void checkClass(File file) {
+ try {
+ byte[] bytes = Files.toByteArray(file);
+ ClassReader classReader = new ClassReader(bytes);
+ classReader.accept(new MyVisitor(file), 0);
+ } catch (IOException e) {
+ System.err.println("Could not read " + file + ": " + e.getLocalizedMessage());
+ System.exit(1);
+ }
+ }
+
+ /**
+ * Prints usage statement.
+ */
+ static void usage(PrintStream out) {
+ out.println("Android TypeDef Remover 1.0");
+ out.println("Copyright (C) 2013 The Android Open Source Project\n");
+ out.println("Usage: rmtypedefs folder1 [folder2 [folder3...]]\n");
+ out.println("Options:");
+ out.println(" -h,--help show this message");
+ out.println(" -q,--quiet quiet");
+ out.println(" -v,--verbose verbose");
+ out.println(" -n,--dry-run dry-run only, leaves files alone");
+ }
+
+ private class MyVisitor extends ClassVisitor {
+
+ /** Class file name */
+ private File mFile;
+
+ /** Class name */
+ private String mName;
+
+ /** Is this class an annotation? */
+ private boolean mAnnotation;
+
+ /** Is this annotation a typedef? Only applies if {@link #mAnnotation} */
+ private boolean mTypedef;
+
+ /** Does the annotation have source retention? Only applies if {@link #mAnnotation} */
+ private boolean mSourceRetention;
+
+ public MyVisitor(File file) {
+ super(ASM4);
+ mFile = file;
+ }
+
+ public void visit(
+ int version,
+ int access,
+ String name,
+ String signature,
+ String superName,
+ String[] interfaces) {
+ mName = name;
+ mAnnotation = interfaces != null && interfaces.length >= 1
+ && ANNOTATION.equals(interfaces[0]);
+
+ // Special case: Also delete the actual @IntDef and @StringDef .class files.
+ // These have class file retention
+ mTypedef = name.equals(INT_DEF) || name.equals(STRING_DEF);
+ }
+
+ public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
+ mTypedef = desc.equals(INT_DEF_DESC) || desc.equals(STRING_DEF_DESC);
+ if (desc.equals(RETENTION_DESC)) {
+ return new AnnotationVisitor(ASM4) {
+ public void visitEnum(String name, String desc, String value) {
+ if (desc.equals(RETENTION_POLICY_DESC)) {
+ mSourceRetention = SOURCE_RETENTION_VALUE.equals(value);
+ }
+ }
+ };
+ }
+ return null;
+ }
+
+ public void visitEnd() {
+ if (mAnnotation && mTypedef) {
+ if (!mSourceRetention && !mName.equals(STRING_DEF) && !mName.equals(INT_DEF)) {
+ System.err.println(mFile + ": Warning: Annotation should be annotated "
+ + "with @Retention(RetentionPolicy.SOURCE)");
+ mHaveError = true;
+ }
+ if (mVerbose) {
+ if (mDryRun) {
+ System.out.println("Would delete " + mFile);
+ } else {
+ System.out.println("Deleting " + mFile);
+ }
+ }
+ if (!mDryRun) {
+ boolean deleted = mFile.delete();
+ if (!deleted) {
+ System.err.println("Could not delete " + mFile);
+ mHaveError = true;
+ }
+ }
+ }
+ }
+ }
+}
+