summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorYohann Roussel <yroussel@google.com>2015-05-19 15:24:30 +0200
committerYohann Roussel <yroussel@google.com>2015-05-26 09:23:11 +0200
commit69dcd62d9251a85037218c1eb45df430870e94e2 (patch)
treef0d445a78c63d2178a72aa57d1514ed0b3bc027e
parentbeab6998369a309f8f078f6d1c2a27565bb67cfa (diff)
downloadtoolchain_jack-69dcd62d9251a85037218c1eb45df430870e94e2.zip
toolchain_jack-69dcd62d9251a85037218c1eb45df430870e94e2.tar.gz
toolchain_jack-69dcd62d9251a85037218c1eb45df430870e94e2.tar.bz2
A transformation for removing "TypeDef" annotations
The removed annotation are those annotated with @StringDef or @IntDef. Also warns if one of the removed annotation has a retention that is not SOURCE. Bug: 21099584 Change-Id: Idc3c04f929320c550260db9517336c49c6b4c5ea
-rw-r--r--jack/src/com/android/jack/Jack.java12
-rw-r--r--jack/src/com/android/jack/jayce/v0002/nodes/NMethod.java2
-rw-r--r--jack/src/com/android/jack/shrob/shrink/TypeShrinker.java112
-rw-r--r--jack/src/com/android/jack/transformations/TypeRemover.java138
-rw-r--r--jack/src/com/android/jack/transformations/typedef/TypeDefRemover.java143
5 files changed, 306 insertions, 101 deletions
diff --git a/jack/src/com/android/jack/Jack.java b/jack/src/com/android/jack/Jack.java
index f6018c4..0bf5664 100644
--- a/jack/src/com/android/jack/Jack.java
+++ b/jack/src/com/android/jack/Jack.java
@@ -236,6 +236,8 @@ import com.android.jack.transformations.parent.TypeAstChecker;
import com.android.jack.transformations.renamepackage.PackageRenamer;
import com.android.jack.transformations.rop.cast.RopCastLegalizer;
import com.android.jack.transformations.threeaddresscode.ThreeAddressCodeBuilder;
+import com.android.jack.transformations.typedef.TypeDefRemover;
+import com.android.jack.transformations.typedef.TypeDefRemover.RemoveTypeDef;
import com.android.jack.transformations.uselessif.UselessIfChecker;
import com.android.jack.transformations.uselessif.UselessIfRemover;
import com.android.jack.util.collect.UnmodifiableCollections;
@@ -543,6 +545,10 @@ public abstract class Jack {
request.addProduction(DependencyInLibraryProduct.class);
}
+ if (config.get(TypeDefRemover.REMOVE_TYPEDEF).booleanValue()) {
+ request.addFeature(TypeDefRemover.RemoveTypeDef.class);
+ }
+
ProductionSet targetProduction = request.getTargetProductions();
FeatureSet features = request.getFeatures();
PlanBuilder<JSession> planBuilder;
@@ -892,6 +898,12 @@ public abstract class Jack {
planBuilder.append(TypeDuplicateRemoverChecker.class);
}
+ if (features.contains(RemoveTypeDef.class)) {
+ SubPlanBuilder<JDefinedClassOrInterface> typePlan =
+ planBuilder.appendSubPlan(JDefinedClassOrInterfaceAdapter.class);
+ typePlan.append(TypeDefRemover.class);
+ }
+
appendStringRefiners(planBuilder);
if (features.contains(Jarjar.class)) {
diff --git a/jack/src/com/android/jack/jayce/v0002/nodes/NMethod.java b/jack/src/com/android/jack/jayce/v0002/nodes/NMethod.java
index e98fb1c..70e18b7 100644
--- a/jack/src/com/android/jack/jayce/v0002/nodes/NMethod.java
+++ b/jack/src/com/android/jack/jayce/v0002/nodes/NMethod.java
@@ -142,7 +142,7 @@ public class NMethod extends NNode implements HasSourceInfo, MethodNode {
public JAbstractMethodBody loadBody(@Nonnull JMethod method) throws JTypeLookupException,
JMethodLookupException {
if (body != null) {
- JSession session = method.getParent(JSession.class);
+ JSession session = method.getEnclosingType().getSession();
ExportSession exportSession = new ExportSession(session.getPhantomLookup(), session,
NodeLevel.FULL);
exportSession.setCurrentMethod(method);
diff --git a/jack/src/com/android/jack/shrob/shrink/TypeShrinker.java b/jack/src/com/android/jack/shrob/shrink/TypeShrinker.java
index 5e455ae..5a95cc4 100644
--- a/jack/src/com/android/jack/shrob/shrink/TypeShrinker.java
+++ b/jack/src/com/android/jack/shrob/shrink/TypeShrinker.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2012 The Android Open Source Project
+ * Copyright (C) 2015 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.
@@ -16,31 +16,16 @@
package com.android.jack.shrob.shrink;
-import com.android.jack.Jack;
-import com.android.jack.ir.ast.JClass;
-import com.android.jack.ir.ast.JClassOrInterface;
-import com.android.jack.ir.ast.JDefinedClass;
import com.android.jack.ir.ast.JDefinedClassOrInterface;
-import com.android.jack.ir.ast.JDefinedInterface;
-import com.android.jack.ir.ast.JInterface;
import com.android.jack.ir.ast.JMethod;
import com.android.jack.ir.ast.JNode;
-import com.android.jack.ir.ast.JSession;
-import com.android.jack.transformations.request.Remove;
-import com.android.jack.transformations.request.TransformationRequest;
+import com.android.jack.transformations.TypeRemover;
import com.android.sched.item.Description;
import com.android.sched.item.Synchronized;
import com.android.sched.schedulable.Constraint;
import com.android.sched.schedulable.RunnableSchedulable;
-import com.android.sched.util.log.LoggerFactory;
import com.android.sched.util.log.TracerFactory;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-
-import javax.annotation.CheckForNull;
import javax.annotation.Nonnull;
/**
@@ -49,97 +34,24 @@ import javax.annotation.Nonnull;
@Description("Removes all types not marked with the KeepMarker")
@Synchronized
@Constraint(need = KeepMarker.class)
-public class TypeShrinker implements RunnableSchedulable<JDefinedClassOrInterface> {
-
- @Nonnull
- private static final Logger logger = LoggerFactory.getLogger();
+public class TypeShrinker extends TypeRemover {
@Nonnull
private final com.android.sched.util.log.Tracer tracer = TracerFactory.getTracer();
- private static void updateSuperTypeList(@Nonnull JDefinedClassOrInterface type) {
- if (type instanceof JDefinedClass) {
- JClass superClass = type.getSuperClass();
- while (mustBeRemoved(superClass)) {
- assert superClass != null;
- for (JInterface i : ((JDefinedClass) superClass).getImplements()) {
- addImplements(type, i);
- }
- superClass = ((JDefinedClass) superClass).getSuperClass();
- }
- ((JDefinedClass) type).setSuperClass(superClass);
- }
- List<JInterface> implementsCopy = new ArrayList<JInterface>(type.getImplements());
- for (JInterface i : implementsCopy) {
- if (mustBeRemoved(i)) {
- JDefinedInterface jDefinedInterface = (JDefinedInterface) i;
- type.remove(jDefinedInterface);
- for (JInterface subInterface : jDefinedInterface.getImplements()) {
- addImplements(type, subInterface);
- }
- }
- }
- }
-
- private static boolean mustBeRemoved(@CheckForNull JClassOrInterface type) {
- return type instanceof JDefinedClassOrInterface && !type.isExternal()
- && !((JNode) type).containsMarker(KeepMarker.class);
- }
-
- private static void addImplements(@Nonnull JDefinedClassOrInterface type, @Nonnull JInterface i) {
- if (!type.getImplements().contains(i)) {
- if (!mustBeRemoved(i)) {
- type.addImplements(i);
- } else {
- for (JInterface subInterface : ((JDefinedInterface) i).getImplements()) {
- addImplements(type, subInterface);
- }
- }
- }
- }
-
@Override
- public synchronized void run(@Nonnull JDefinedClassOrInterface type) throws Exception {
- boolean toRemove = !type.containsMarker(KeepMarker.class);
- if (toRemove) {
- TransformationRequest request = new TransformationRequest(type);
- request.append(new Remove(type));
- logger.log(Level.INFO, "Removed type {0}", Jack.getUserFriendlyFormatter().getName(type));
- JClassOrInterface enclosing = type.getEnclosingType();
- if (enclosing instanceof JDefinedClassOrInterface) {
- JDefinedClassOrInterface enclosingType = (JDefinedClassOrInterface) enclosing;
- enclosingType.removeMemberType(type);
- }
- type.getParent(JSession.class).removeTypeToEmit(type);
- request.commit();
- } else {
- updateSuperTypeList(type);
- updateEnclosingType(type);
- if (type instanceof JDefinedClass) {
- updateEnclosingMethod((JDefinedClass) type);
- }
- }
- tracer.getStatistic(ShrinkStatistic.TYPES_REMOVED).add(toRemove);
+ protected boolean mustBeRemoved(@Nonnull JDefinedClassOrInterface type) {
+ return !type.isExternal() && !((JNode) type).containsMarker(KeepMarker.class);
}
- private void updateEnclosingType(@Nonnull JDefinedClassOrInterface type) {
- JClassOrInterface enclosingType = type.getEnclosingType();
- while (enclosingType instanceof JDefinedClassOrInterface) {
- if (((JNode) enclosingType).containsMarker(KeepMarker.class) || enclosingType.isExternal()) {
- break;
- }
- enclosingType = ((JDefinedClassOrInterface) enclosingType).getEnclosingType();
- }
- type.setEnclosingType(enclosingType);
+ @Override
+ public void run(@Nonnull JDefinedClassOrInterface type) throws Exception {
+ super.run(type);
+ tracer.getStatistic(ShrinkStatistic.TYPES_REMOVED).add(mustBeRemoved(type));
}
- private void updateEnclosingMethod(@Nonnull JDefinedClass type) {
- JMethod enclosingMethod = type.getEnclosingMethod();
- if (enclosingMethod != null
- && !enclosingMethod.containsMarker(KeepMarker.class)) {
- assert !enclosingMethod.isExternal();
- type.setEnclosingMethod(null);
- }
+ @Override
+ protected boolean isPlannedForRemoval(@Nonnull JMethod method) {
+ return !method.isExternal() && !((JNode) method).containsMarker(KeepMarker.class);
}
-
}
diff --git a/jack/src/com/android/jack/transformations/TypeRemover.java b/jack/src/com/android/jack/transformations/TypeRemover.java
new file mode 100644
index 0000000..f81c203
--- /dev/null
+++ b/jack/src/com/android/jack/transformations/TypeRemover.java
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2015 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.jack.transformations;
+
+import com.android.jack.Jack;
+import com.android.jack.ir.ast.JClass;
+import com.android.jack.ir.ast.JClassOrInterface;
+import com.android.jack.ir.ast.JDefinedClass;
+import com.android.jack.ir.ast.JDefinedClassOrInterface;
+import com.android.jack.ir.ast.JDefinedInterface;
+import com.android.jack.ir.ast.JInterface;
+import com.android.jack.ir.ast.JMethod;
+import com.android.jack.transformations.request.Remove;
+import com.android.jack.transformations.request.TransformationRequest;
+import com.android.sched.item.Synchronized;
+import com.android.sched.schedulable.RunnableSchedulable;
+import com.android.sched.util.log.LoggerFactory;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import javax.annotation.CheckForNull;
+import javax.annotation.Nonnull;
+
+/**
+ * Abstract schedulable removing a selection of types.
+ */
+@Synchronized
+public abstract class TypeRemover implements RunnableSchedulable<JDefinedClassOrInterface> {
+
+ @Nonnull
+ private static final Logger logger = LoggerFactory.getLogger();
+
+ private void updateSuperTypeList(@Nonnull JDefinedClassOrInterface type) {
+ if (type instanceof JDefinedClass) {
+ JClass superClass = type.getSuperClass();
+ while (mustBeRemovedInternal(superClass)) {
+ assert superClass != null;
+ for (JInterface i : ((JDefinedClass) superClass).getImplements()) {
+ addImplements(type, i);
+ }
+ superClass = ((JDefinedClass) superClass).getSuperClass();
+ }
+ ((JDefinedClass) type).setSuperClass(superClass);
+ }
+ List<JInterface> implementsCopy = new ArrayList<JInterface>(type.getImplements());
+ for (JInterface i : implementsCopy) {
+ if (mustBeRemovedInternal(i)) {
+ JDefinedInterface jDefinedInterface = (JDefinedInterface) i;
+ type.remove(jDefinedInterface);
+ for (JInterface subInterface : jDefinedInterface.getImplements()) {
+ addImplements(type, subInterface);
+ }
+ }
+ }
+ }
+
+ private boolean mustBeRemovedInternal(@CheckForNull JClassOrInterface type) {
+ if (type instanceof JDefinedClassOrInterface) {
+ return mustBeRemoved((JDefinedClassOrInterface) type);
+ }
+ return false;
+ }
+
+ protected abstract boolean mustBeRemoved(@Nonnull JDefinedClassOrInterface type);
+
+ protected abstract boolean isPlannedForRemoval(@Nonnull JMethod method);
+
+ private void addImplements(@Nonnull JDefinedClassOrInterface type, @Nonnull JInterface i) {
+ if (!type.getImplements().contains(i)) {
+ if (!mustBeRemovedInternal(i)) {
+ type.addImplements(i);
+ } else {
+ for (JInterface subInterface : ((JDefinedInterface) i).getImplements()) {
+ addImplements(type, subInterface);
+ }
+ }
+ }
+ }
+
+ @Override
+ public synchronized void run(@Nonnull JDefinedClassOrInterface type) throws Exception {
+ boolean toRemove = mustBeRemoved(type);
+ if (toRemove) {
+ TransformationRequest request = new TransformationRequest(type);
+ request.append(new Remove(type));
+ logger.log(Level.INFO, "Removed type {0}", Jack.getUserFriendlyFormatter().getName(type));
+ JClassOrInterface enclosing = type.getEnclosingType();
+ if (enclosing instanceof JDefinedClassOrInterface) {
+ JDefinedClassOrInterface enclosingType = (JDefinedClassOrInterface) enclosing;
+ enclosingType.removeMemberType(type);
+ }
+ type.getSession().removeTypeToEmit(type);
+ request.commit();
+ } else {
+ updateSuperTypeList(type);
+ updateEnclosingType(type);
+ if (type instanceof JDefinedClass) {
+ updateEnclosingMethod((JDefinedClass) type);
+ }
+ }
+ }
+
+ private void updateEnclosingType(@Nonnull JDefinedClassOrInterface type) {
+ JClassOrInterface enclosingType = type.getEnclosingType();
+ while (enclosingType instanceof JDefinedClassOrInterface) {
+ if (!mustBeRemovedInternal(enclosingType) || enclosingType.isExternal()) {
+ break;
+ }
+ enclosingType = ((JDefinedClassOrInterface) enclosingType).getEnclosingType();
+ }
+ type.setEnclosingType(enclosingType);
+ }
+
+ private void updateEnclosingMethod(@Nonnull JDefinedClass type) {
+ JMethod enclosingMethod = type.getEnclosingMethod();
+ if (enclosingMethod != null && isPlannedForRemoval(enclosingMethod)) {
+ assert !enclosingMethod.isExternal();
+ type.setEnclosingMethod(null);
+ }
+ }
+} \ No newline at end of file
diff --git a/jack/src/com/android/jack/transformations/typedef/TypeDefRemover.java b/jack/src/com/android/jack/transformations/typedef/TypeDefRemover.java
new file mode 100644
index 0000000..b63ea93
--- /dev/null
+++ b/jack/src/com/android/jack/transformations/typedef/TypeDefRemover.java
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 2012 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.jack.transformations.typedef;
+
+import com.android.jack.Jack;
+import com.android.jack.ir.ast.JDefinedAnnotationType;
+import com.android.jack.ir.ast.JDefinedClassOrInterface;
+import com.android.jack.ir.ast.JMethod;
+import com.android.jack.ir.ast.JRetentionPolicy;
+import com.android.jack.reporting.Reportable;
+import com.android.jack.reporting.Reporter.Severity;
+import com.android.jack.transformations.TypeRemover;
+import com.android.jack.transformations.typedef.TypeDefRemover.RemoveTypeDef;
+import com.android.sched.item.Description;
+import com.android.sched.item.Feature;
+import com.android.sched.item.Synchronized;
+import com.android.sched.schedulable.RunnableSchedulable;
+import com.android.sched.schedulable.Support;
+import com.android.sched.util.config.HasKeyId;
+import com.android.sched.util.config.id.BooleanPropertyId;
+
+import javax.annotation.Nonnull;
+
+/**
+ * A {@link RunnableSchedulable} removing @StringDef, @IntDef and all annotations
+ * annotated with them.
+ */
+@Description("Removes @StringDef, @IntDef and all annotations annotated with them")
+@Synchronized
+@Support(RemoveTypeDef.class)
+@HasKeyId
+public class TypeDefRemover extends TypeRemover {
+
+ @Nonnull
+ public static final BooleanPropertyId REMOVE_TYPEDEF = BooleanPropertyId.create(
+ "jack.android.remove-typedef",
+ "Removes @StringDef, @IntDef and all annotations annotated with them")
+ .addDefaultValue(false);
+
+ /**
+ * A {@link Feature} allowing to remove @StringDef, @IntDef and all annotations annotated with
+ * them.
+ */
+ @Description("Removes @StringDef, @IntDef and all annotations annotated with them")
+ public static class RemoveTypeDef implements Feature {
+ }
+
+ private static class InvalidRetentionForTypeDef implements Reportable {
+
+ @Nonnull
+ private final JDefinedAnnotationType typeDef;
+
+ public InvalidRetentionForTypeDef(@Nonnull JDefinedAnnotationType typeDef) {
+ this.typeDef = typeDef;
+ }
+
+ @Override
+ @Nonnull
+ public String getMessage() {
+ return "Annotation @" + Jack.getUserFriendlyFormatter().getName(typeDef)
+ + "should be annotated with @Retention(RetentionPolicy.SOURCE)";
+ }
+
+ @Override
+ @Nonnull
+ public ProblemLevel getDefaultProblemLevel() {
+ return ProblemLevel.WARNING;
+ }
+ }
+
+ private static class InvalidTypeDefTarget implements Reportable {
+
+ @Nonnull
+ private final JDefinedClassOrInterface annotated;
+
+ public InvalidTypeDefTarget(@Nonnull JDefinedClassOrInterface annotated) {
+ this.annotated = annotated;
+ }
+
+ @Override
+ @Nonnull
+ public String getMessage() {
+ return "Type " + Jack.getUserFriendlyFormatter().getName(annotated)
+ + " should not be annotated with @IntDef or @StringDef,"
+ + " only annotations are valid targets";
+ }
+
+ @Override
+ @Nonnull
+ public ProblemLevel getDefaultProblemLevel() {
+ return ProblemLevel.WARNING;
+ }
+ }
+
+ @Nonnull
+ private final JDefinedAnnotationType stringDef =
+ Jack.getSession().getLookup().getAnnotationType("Landroid/annotation/StringDef;");
+
+ @Nonnull
+ private final JDefinedAnnotationType intDef =
+ Jack.getSession().getLookup().getAnnotationType("Landroid/annotation/IntDef;");
+
+ @Override
+ protected boolean mustBeRemoved(@Nonnull JDefinedClassOrInterface type) {
+ if (type == stringDef || type == intDef) {
+ return true;
+ }
+ if (type instanceof JDefinedAnnotationType) {
+ if ((!type.getAnnotations(stringDef).isEmpty()) || !type.getAnnotations(intDef).isEmpty()) {
+ JDefinedAnnotationType typeDef = (JDefinedAnnotationType) type;
+ if (typeDef.getRetentionPolicy() != JRetentionPolicy.SOURCE) {
+ type.getSession().getReporter().report(Severity.NON_FATAL,
+ new InvalidRetentionForTypeDef(typeDef));
+ }
+ return true;
+ }
+ } else if ((!type.getAnnotations(stringDef).isEmpty())
+ || !type.getAnnotations(intDef).isEmpty()) {
+ Jack.getSession().getReporter().report(Severity.NON_FATAL,
+ new InvalidTypeDefTarget(type));
+ }
+ return false;
+ }
+
+ @Override
+ protected boolean isPlannedForRemoval(@Nonnull JMethod method) {
+ return mustBeRemoved(method.getEnclosingType());
+ }
+}