blob: 4fdad6a95c88e8d50d9c6d80a1dd2529a50338bc [file] [log] [blame]
// Copyright (c) 2019, the R8 project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.shaking;
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.DexAnnotation;
import com.android.tools.r8.graph.DexAnnotationElement;
import com.android.tools.r8.graph.DexEncodedAnnotation;
import com.android.tools.r8.graph.DexEncodedField;
import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.graph.DexField;
import com.android.tools.r8.graph.DexProgramClass;
import com.android.tools.r8.graph.DexReference;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.DexValue;
import com.android.tools.r8.graph.DexValue.DexItemBasedValueString;
import com.android.tools.r8.graph.DexValue.DexValueAnnotation;
import com.android.tools.r8.graph.DexValue.DexValueArray;
import com.android.tools.r8.graph.DexValue.DexValueEnum;
import com.android.tools.r8.graph.DexValue.DexValueType;
import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.utils.ArrayUtils;
public class AnnotationFixer {
private final GraphLens lens;
public AnnotationFixer(GraphLens lens) {
this.lens = lens;
}
public void run(Iterable<DexProgramClass> classes) {
for (DexProgramClass clazz : classes) {
clazz.setAnnotations(clazz.annotations().rewrite(this::rewriteAnnotation));
clazz.forEachMethod(this::processMethod);
clazz.forEachField(this::processField);
}
}
private void processMethod(DexEncodedMethod method) {
method.setAnnotations(method.annotations().rewrite(this::rewriteAnnotation));
method.parameterAnnotationsList =
method.parameterAnnotationsList.rewrite(
dexAnnotationSet -> dexAnnotationSet.rewrite(this::rewriteAnnotation));
}
private void processField(DexEncodedField field) {
field.setAnnotations(field.annotations().rewrite(this::rewriteAnnotation));
}
private DexAnnotation rewriteAnnotation(DexAnnotation original) {
return original.rewrite(this::rewriteEncodedAnnotation);
}
private DexEncodedAnnotation rewriteEncodedAnnotation(DexEncodedAnnotation original) {
DexEncodedAnnotation rewritten =
original.rewrite(lens::lookupType, this::rewriteAnnotationElement);
assert rewritten != null;
return rewritten;
}
private DexAnnotationElement rewriteAnnotationElement(DexAnnotationElement original) {
DexValue rewrittenValue = rewriteComplexValue(original.value);
if (rewrittenValue != original.value) {
return new DexAnnotationElement(original.name, rewrittenValue);
}
return original;
}
private DexValue rewriteComplexValue(DexValue value) {
if (value.isDexValueArray()) {
DexValue[] originalValues = value.asDexValueArray().getValues();
DexValue[] rewrittenValues =
ArrayUtils.map(DexValue[].class, originalValues, this::rewriteComplexValue);
if (rewrittenValues != originalValues) {
return new DexValueArray(rewrittenValues);
}
} else if (value.isDexValueAnnotation()) {
DexValueAnnotation original = value.asDexValueAnnotation();
DexEncodedAnnotation rewritten = rewriteEncodedAnnotation(original.getValue());
if (original.value == rewritten) {
return value;
}
return new DexValueAnnotation(rewritten);
}
return rewriteNestedValue(value);
}
private DexValue rewriteNestedValue(DexValue value) {
if (value.isDexItemBasedValueString()) {
DexItemBasedValueString valueString = value.asDexItemBasedValueString();
DexReference original = valueString.value;
DexReference rewritten = lens.lookupReference(original);
if (original != rewritten) {
return new DexItemBasedValueString(rewritten, valueString.getNameComputationInfo());
}
} else if (value.isDexValueEnum()) {
DexField original = value.asDexValueEnum().value;
DexField rewritten = lens.lookupField(original);
if (original != rewritten) {
return new DexValueEnum(rewritten);
}
} else if (value.isDexValueField()) {
throw new Unreachable("Unexpected field in annotation");
} else if (value.isDexValueMethod()) {
throw new Unreachable("Unexpected method in annotation");
} else if (value.isDexValueMethodHandle()) {
throw new Unreachable("Unexpected method handle in annotation");
} else if (value.isDexValueMethodType()) {
throw new Unreachable("Unexpected method type in annotation");
} else if (value.isDexValueString()) {
// If we identified references in the string it would be a DexItemBasedValueString.
} else if (value.isDexValueType()) {
DexType originalType = value.asDexValueType().value;
DexType rewrittenType = lens.lookupType(originalType);
if (rewrittenType != originalType) {
return new DexValueType(rewrittenType);
}
} else {
// Assert that we have not forgotten a value.
assert !value.isNestedDexValue();
}
return value;
}
}