Move kotlin metadata removal to annotation remover
Change-Id: Ic72a22405c87b50123bb4b549385c54417813f55
diff --git a/src/main/java/com/android/tools/r8/graph/DexEncodedField.java b/src/main/java/com/android/tools/r8/graph/DexEncodedField.java
index 7095940..ada1c8a 100644
--- a/src/main/java/com/android/tools/r8/graph/DexEncodedField.java
+++ b/src/main/java/com/android/tools/r8/graph/DexEncodedField.java
@@ -346,6 +346,7 @@
this.genericSignature = genericSignature;
}
+ @Override
public void clearGenericSignature() {
this.genericSignature = FieldTypeSignature.noSignature();
}
diff --git a/src/main/java/com/android/tools/r8/graph/DexEncodedMember.java b/src/main/java/com/android/tools/r8/graph/DexEncodedMember.java
index f596146..e1bb25e 100644
--- a/src/main/java/com/android/tools/r8/graph/DexEncodedMember.java
+++ b/src/main/java/com/android/tools/r8/graph/DexEncodedMember.java
@@ -28,6 +28,8 @@
public abstract void clearKotlinInfo();
+ public abstract void clearGenericSignature();
+
public DexType getHolderType() {
return getReference().getHolderType();
}
diff --git a/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java b/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
index 9051374..434b091 100644
--- a/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
+++ b/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
@@ -650,10 +650,6 @@
this.kotlinMemberInfo = kotlinMemberInfo;
}
- public void clearKotlinMemberInfo() {
- kotlinMemberInfo = getNoKotlinInfo();
- }
-
public boolean isKotlinFunction() {
return kotlinMemberInfo.isFunction();
}
@@ -1504,6 +1500,7 @@
this.genericSignature = genericSignature;
}
+ @Override
public void clearGenericSignature() {
this.genericSignature = MethodTypeSignature.noSignature();
}
diff --git a/src/main/java/com/android/tools/r8/graph/DexProgramClass.java b/src/main/java/com/android/tools/r8/graph/DexProgramClass.java
index 315b8a1..6be5551 100644
--- a/src/main/java/com/android/tools/r8/graph/DexProgramClass.java
+++ b/src/main/java/com/android/tools/r8/graph/DexProgramClass.java
@@ -472,10 +472,14 @@
public void setKotlinInfo(KotlinClassLevelInfo kotlinInfo) {
assert kotlinInfo != null;
- assert this.kotlinInfo == getNoKotlinInfo() || kotlinInfo == getNoKotlinInfo();
+ assert this.kotlinInfo == getNoKotlinInfo();
this.kotlinInfo = kotlinInfo;
}
+ public void clearKotlinInfo() {
+ this.kotlinInfo = getNoKotlinInfo();
+ }
+
@Override
boolean internalClassOrInterfaceMayHaveInitializationSideEffects(
AppView<?> appView,
diff --git a/src/main/java/com/android/tools/r8/graph/ProgramMethod.java b/src/main/java/com/android/tools/r8/graph/ProgramMethod.java
index f4aa43b..5a58189 100644
--- a/src/main/java/com/android/tools/r8/graph/ProgramMethod.java
+++ b/src/main/java/com/android/tools/r8/graph/ProgramMethod.java
@@ -101,7 +101,7 @@
@Override
public void clearKotlinInfo() {
- getDefinition().clearKotlinMemberInfo();
+ getDefinition().clearKotlinInfo();
}
public MethodPosition getPosition() {
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataEnqueuerExtension.java b/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataEnqueuerExtension.java
index 2907d72..70a51ed 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataEnqueuerExtension.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataEnqueuerExtension.java
@@ -5,7 +5,6 @@
package com.android.tools.r8.kotlin;
import static com.android.tools.r8.kotlin.KotlinClassMetadataReader.hasKotlinClassMetadataAnnotation;
-import static com.android.tools.r8.kotlin.KotlinMetadataUtils.getNoKotlinInfo;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexClass;
@@ -23,6 +22,7 @@
import com.android.tools.r8.ir.optimize.info.OptimizationFeedbackSimple;
import com.android.tools.r8.shaking.Enqueuer;
import com.android.tools.r8.shaking.Enqueuer.EnqueuerDefinitionSupplier;
+import com.android.tools.r8.shaking.KeepClassInfo;
import com.google.common.collect.Sets;
import java.util.Set;
@@ -49,33 +49,31 @@
@Override
public void done(Enqueuer enqueuer) {
- DexType kotlinMetadataType = appView.dexItemFactory().kotlinMetadataType;
- DexClass kotlinMetadataClass =
- appView.appInfo().definitionForWithoutExistenceAssert(kotlinMetadataType);
// In the first round of tree shaking build up all metadata such that it can be traced later.
- boolean keepMetadata =
- (kotlinMetadataClass == null
- || kotlinMetadataClass.isNotProgramClass()
- || enqueuer.isPinned(kotlinMetadataType))
- && appView
- .options()
- .getProguardConfiguration()
- .getKeepAttributes()
- .runtimeVisibleAnnotations;
+ boolean keepKotlinMetadata =
+ KeepClassInfo.isKotlinMetadataClassKept(
+ appView.dexItemFactory(),
+ appView.appInfo()::definitionForWithoutExistenceAssert,
+ enqueuer::getKeepInfo);
+ // In the first round of tree shaking build up all metadata such that it can be traced later.
if (enqueuer.getMode().isInitialTreeShaking()) {
Set<DexMethod> keepByteCodeFunctions = Sets.newIdentityHashSet();
Set<DexProgramClass> localOrAnonymousClasses = Sets.newIdentityHashSet();
enqueuer.forAllLiveClasses(
clazz -> {
assert clazz.getKotlinInfo().isNoKotlinInformation();
- if (!keepMetadata || !enqueuer.isPinned(clazz.getType())) {
+ if (enqueuer
+ .getKeepInfo(clazz)
+ .isKotlinMetadataRemovalAllowed(appView.options(), keepKotlinMetadata)) {
if (KotlinClassMetadataReader.isLambda(appView, clazz)
&& clazz.hasClassInitializer()) {
feedback.classInitializerMayBePostponed(clazz.getClassInitializer());
}
- clazz.setKotlinInfo(getNoKotlinInfo());
+ clazz.clearKotlinInfo();
clazz.removeAnnotations(
- annotation -> annotation.getAnnotationType() == kotlinMetadataType);
+ annotation ->
+ annotation.getAnnotationType()
+ == appView.dexItemFactory().kotlinMetadataType);
} else {
clazz.setKotlinInfo(
KotlinClassMetadataReader.getKotlinInfo(
@@ -109,17 +107,18 @@
assert enqueuer.getMode().isFinalTreeShaking();
enqueuer.forAllLiveClasses(
clazz -> {
- if (!enqueuer.isPinned(clazz.getType())) {
- clazz.setKotlinInfo(getNoKotlinInfo());
+ if (enqueuer
+ .getKeepInfo(clazz)
+ .isKotlinMetadataRemovalAllowed(appView.options(), keepKotlinMetadata)) {
+ clazz.clearKotlinInfo();
clazz.members().forEach(DexEncodedMember::clearKotlinInfo);
clazz.removeAnnotations(
- annotation -> annotation.getAnnotationType() == kotlinMetadataType);
+ annotation ->
+ annotation.getAnnotationType()
+ == appView.dexItemFactory().kotlinMetadataType);
} else {
- boolean shouldHaveKotlinInfo =
- keepMetadata
- && hasKotlinClassMetadataAnnotation(clazz, definitionsForContext(clazz));
- boolean hasKotlinInfo = clazz.getKotlinInfo() != getNoKotlinInfo();
- assert hasKotlinInfo == shouldHaveKotlinInfo;
+ assert hasKotlinClassMetadataAnnotation(clazz, definitionsForContext(clazz))
+ == !clazz.getKotlinInfo().isNoKotlinInformation();
}
});
}
diff --git a/src/main/java/com/android/tools/r8/shaking/AnnotationRemover.java b/src/main/java/com/android/tools/r8/shaking/AnnotationRemover.java
index e1eabf2..567b7cb 100644
--- a/src/main/java/com/android/tools/r8/shaking/AnnotationRemover.java
+++ b/src/main/java/com/android/tools/r8/shaking/AnnotationRemover.java
@@ -10,7 +10,7 @@
import com.android.tools.r8.graph.DexClass;
import com.android.tools.r8.graph.DexDefinition;
import com.android.tools.r8.graph.DexEncodedAnnotation;
-import com.android.tools.r8.graph.DexEncodedField;
+import com.android.tools.r8.graph.DexEncodedMember;
import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.DexProgramClass;
@@ -168,11 +168,12 @@
stripAttributes(clazz);
clazz.setAnnotations(
clazz.annotations().rewrite(annotation -> rewriteAnnotation(clazz, annotation)));
- // Kotlin properties are split over fields and methods. Check if any is pinned before pruning
- // the information.
+ // Kotlin metadata for classes are removed in the KotlinMetadataEnqueuerExtension. Kotlin
+ // properties are split over fields and methods. Check if any is pinned before pruning the
+ // information.
Set<KotlinPropertyInfo> pinnedKotlinProperties = Sets.newIdentityHashSet();
- clazz.forEachMethod(method -> processMethod(method, clazz, pinnedKotlinProperties));
- clazz.forEachField(field -> processField(field, clazz, pinnedKotlinProperties));
+ clazz.forEachProgramMember(
+ member -> processMember(member.getDefinition(), clazz, pinnedKotlinProperties));
clazz.forEachProgramMember(
member -> {
KotlinMemberLevelInfo kotlinInfo = member.getKotlinInfo();
@@ -182,40 +183,43 @@
}
});
}
+ assert verifyNoKeptKotlinMembersForClassesWithNoKotlinInfo();
}
- private void processMethod(
- DexEncodedMethod method,
- DexProgramClass clazz,
- Set<KotlinPropertyInfo> pinnedKotlinProperties) {
- method.setAnnotations(
- method.annotations().rewrite(annotation -> rewriteAnnotation(method, annotation)));
- method.parameterAnnotationsList =
- method.parameterAnnotationsList.keepIf(this::filterParameterAnnotations);
- KeepMethodInfo methodInfo = appView.getKeepInfo().getMethodInfo(method, clazz);
- if (methodInfo.isSignatureAttributeRemovalAllowed(options)) {
- method.clearGenericSignature();
+ private boolean verifyNoKeptKotlinMembersForClassesWithNoKotlinInfo() {
+ for (DexProgramClass clazz : appView.appInfo().classes()) {
+ if (clazz.getKotlinInfo().isNoKotlinInformation()) {
+ clazz.forEachProgramMember(
+ member -> {
+ assert member.getKotlinInfo().isNoKotlinInformation()
+ : "Should have pruned kotlin info";
+ });
+ }
}
- if (!methodInfo.isPinned() && method.getKotlinInfo().isFunction()) {
- method.clearKotlinMemberInfo();
- }
- if (methodInfo.isPinned() && method.getKotlinInfo().isProperty()) {
- pinnedKotlinProperties.add(method.getKotlinInfo().asProperty());
- }
+ return true;
}
- private void processField(
- DexEncodedField field,
+ private void processMember(
+ DexEncodedMember<?, ?> member,
DexProgramClass clazz,
Set<KotlinPropertyInfo> pinnedKotlinProperties) {
- field.setAnnotations(
- field.annotations().rewrite(annotation -> rewriteAnnotation(field, annotation)));
- KeepFieldInfo fieldInfo = appView.getKeepInfo().getFieldInfo(field, clazz);
- if (fieldInfo.isSignatureAttributeRemovalAllowed(options)) {
- field.clearGenericSignature();
+ member.setAnnotations(
+ member.annotations().rewrite(annotation -> rewriteAnnotation(member, annotation)));
+ if (member.isDexEncodedMethod()) {
+ DexEncodedMethod method = member.asDexEncodedMethod();
+ method.parameterAnnotationsList =
+ method.parameterAnnotationsList.keepIf(this::filterParameterAnnotations);
}
- if (fieldInfo.isPinned() && field.getKotlinInfo().isProperty()) {
- pinnedKotlinProperties.add(field.getKotlinInfo().asProperty());
+ KeepMemberInfo<?, ?> memberInfo = appView.getKeepInfo().getMemberInfo(member, clazz);
+ if (memberInfo.isSignatureAttributeRemovalAllowed(options)) {
+ member.clearGenericSignature();
+ }
+ if (!member.getKotlinInfo().isProperty() && memberInfo.isKotlinMetadataRemovalAllowed(clazz)) {
+ member.clearKotlinInfo();
+ }
+ // Postpone removal of kotlin property info until we have seen all fields, setters and getters.
+ if (member.getKotlinInfo().isProperty() && !memberInfo.isKotlinMetadataRemovalAllowed(clazz)) {
+ pinnedKotlinProperties.add(member.getKotlinInfo().asProperty());
}
}
@@ -266,20 +270,18 @@
// need to keep the enclosing method and inner classes attributes, if requested. In Proguard
// compatibility mode we keep these attributes independent of whether the given class is kept.
// In full mode we remove the attribute if not both sides are kept.
+ KeepClassInfo keepInfo = appView.getKeepInfo().getClassInfo(clazz);
clazz.removeEnclosingMethodAttribute(
enclosingMethodAttribute ->
- appView
- .getKeepInfo()
- .getClassInfo(clazz)
- .isEnclosingMethodAttributeRemovalAllowed(
- options, enclosingMethodAttribute, appView));
+ keepInfo.isEnclosingMethodAttributeRemovalAllowed(
+ options, enclosingMethodAttribute, appView));
// It is important that the call to getEnclosingMethodAttribute is done after we potentially
// pruned it above.
clazz.removeInnerClasses(
attribute ->
canRemoveInnerClassAttribute(clazz, attribute, clazz.getEnclosingMethodAttribute()));
if (clazz.getClassSignature().isValid()
- && appView.getKeepInfo().getClassInfo(clazz).isSignatureAttributeRemovalAllowed(options)) {
+ && keepInfo.isSignatureAttributeRemovalAllowed(options)) {
clazz.clearClassSignature();
}
}
diff --git a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
index 1023e70..61db1bf 100644
--- a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
+++ b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
@@ -653,8 +653,8 @@
return clazz;
}
- public boolean isPinned(DexType type) {
- return keepInfo.isPinned(type, appInfo);
+ public KeepClassInfo getKeepInfo(DexProgramClass clazz) {
+ return keepInfo.getClassInfo(clazz);
}
private void addLiveNonProgramType(
diff --git a/src/main/java/com/android/tools/r8/shaking/GlobalKeepInfoConfiguration.java b/src/main/java/com/android/tools/r8/shaking/GlobalKeepInfoConfiguration.java
index cc11777..07f625d 100644
--- a/src/main/java/com/android/tools/r8/shaking/GlobalKeepInfoConfiguration.java
+++ b/src/main/java/com/android/tools/r8/shaking/GlobalKeepInfoConfiguration.java
@@ -21,4 +21,6 @@
boolean isKeepEnclosingMethodAttributeEnabled();
boolean isKeepInnerClassesAttributeEnabled();
+
+ boolean isKeepRuntimeVisibleAnnotationsEnabled();
}
diff --git a/src/main/java/com/android/tools/r8/shaking/KeepClassInfo.java b/src/main/java/com/android/tools/r8/shaking/KeepClassInfo.java
index 40b2c9e..a12ca25 100644
--- a/src/main/java/com/android/tools/r8/shaking/KeepClassInfo.java
+++ b/src/main/java/com/android/tools/r8/shaking/KeepClassInfo.java
@@ -3,6 +3,13 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.shaking;
+import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.DexClass;
+import com.android.tools.r8.graph.DexItemFactory;
+import com.android.tools.r8.graph.DexProgramClass;
+import com.android.tools.r8.graph.DexType;
+import java.util.function.Function;
+
/** Immutable keep requirements for a class. */
public final class KeepClassInfo extends KeepInfo<KeepClassInfo.Builder, KeepClassInfo> {
@@ -41,6 +48,31 @@
&& !internalIsAccessModificationRequiredForRepackaging();
}
+ public boolean isKotlinMetadataRemovalAllowed(
+ GlobalKeepInfoConfiguration configuration, boolean kotlinMetadataKept) {
+ return !kotlinMetadataKept
+ || !isPinned()
+ || !configuration.isKeepRuntimeVisibleAnnotationsEnabled();
+ }
+
+ public static boolean isKotlinMetadataClassKept(AppView<?> appView) {
+ return isKotlinMetadataClassKept(
+ appView.dexItemFactory(),
+ appView.appInfo()::definitionForWithoutExistenceAssert,
+ appView.getKeepInfo()::getClassInfo);
+ }
+
+ public static boolean isKotlinMetadataClassKept(
+ DexItemFactory factory,
+ Function<DexType, DexClass> definitionForWithoutExistenceAssert,
+ Function<DexProgramClass, KeepClassInfo> getClassInfo) {
+ DexType kotlinMetadataType = factory.kotlinMetadataType;
+ DexClass kotlinMetadataClass = definitionForWithoutExistenceAssert.apply(kotlinMetadataType);
+ return kotlinMetadataClass == null
+ || kotlinMetadataClass.isNotProgramClass()
+ || getClassInfo.apply(kotlinMetadataClass.asProgramClass()).isPinned();
+ }
+
@Override
public boolean isTop() {
return this.equals(top());
diff --git a/src/main/java/com/android/tools/r8/shaking/KeepMemberInfo.java b/src/main/java/com/android/tools/r8/shaking/KeepMemberInfo.java
index 770e84c..46d8fa2 100644
--- a/src/main/java/com/android/tools/r8/shaking/KeepMemberInfo.java
+++ b/src/main/java/com/android/tools/r8/shaking/KeepMemberInfo.java
@@ -3,6 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.shaking;
+import com.android.tools.r8.graph.DexProgramClass;
import com.android.tools.r8.shaking.KeepInfo.Builder;
/** Immutable keep requirements for a member. */
@@ -18,4 +19,10 @@
return configuration.isRepackagingEnabled()
&& !internalIsAccessModificationRequiredForRepackaging();
}
+
+ public boolean isKotlinMetadataRemovalAllowed(DexProgramClass holder) {
+ // Checking the holder for missing kotlin information relies on the holder being processed
+ // before members.
+ return holder.getKotlinInfo().isNoKotlinInformation() || !isPinned();
+ }
}
diff --git a/src/main/java/com/android/tools/r8/utils/InternalOptions.java b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
index 0263e28..e08fe12 100644
--- a/src/main/java/com/android/tools/r8/utils/InternalOptions.java
+++ b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
@@ -615,6 +615,11 @@
return proguardConfiguration.getKeepAttributes().innerClasses;
}
+ @Override
+ public boolean isKeepRuntimeVisibleAnnotationsEnabled() {
+ return proguardConfiguration.getKeepAttributes().runtimeVisibleAnnotations;
+ }
+
/**
* If any non-static class merging is enabled, information about types referred to by instanceOf
* and check cast instructions needs to be collected.