blob: 883be66324d9e06c73abe6502bd26eba80fc952e [file] [log] [blame]
// Copyright (c) 2020, 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.kotlin;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexDefinitionSupplier;
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.kotlin.Kotlin.ClassClassifiers;
import com.android.tools.r8.naming.NamingLens;
import com.android.tools.r8.shaking.EnqueuerMetadataTraceable;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
import kotlinx.metadata.KmAnnotationArgument;
import kotlinx.metadata.KmAnnotationArgument.AnnotationValue;
import kotlinx.metadata.KmAnnotationArgument.ArrayValue;
import kotlinx.metadata.KmAnnotationArgument.EnumValue;
import kotlinx.metadata.KmAnnotationArgument.KClassValue;
abstract class KotlinAnnotationArgumentInfo implements EnqueuerMetadataTraceable {
private static final Map<String, KotlinAnnotationArgumentInfo> EMPTY_ARGUMENTS =
ImmutableMap.of();
abstract boolean rewrite(
Consumer<KmAnnotationArgument<?>> consumer, AppView<?> appView, NamingLens namingLens);
private static KotlinAnnotationArgumentInfo createArgument(
KmAnnotationArgument<?> arg, DexItemFactory factory) {
if (arg instanceof KClassValue) {
return KotlinAnnotationClassValueInfo.create((KClassValue) arg, factory);
} else if (arg instanceof EnumValue) {
return KotlinAnnotationEnumValueInfo.create((EnumValue) arg, factory);
} else if (arg instanceof AnnotationValue) {
return KotlinAnnotationAnnotationValueInfo.create((AnnotationValue) arg, factory);
} else if (arg instanceof ArrayValue) {
return KotlinAnnotationArrayValueInfo.create((ArrayValue) arg, factory);
} else {
return KotlinAnnotationPrimitiveArgumentInfo.create(arg);
}
}
static Map<String, KotlinAnnotationArgumentInfo> create(
Map<String, KmAnnotationArgument<?>> arguments, DexItemFactory factory) {
if (arguments.isEmpty()) {
return EMPTY_ARGUMENTS;
}
LinkedHashMap<String, KotlinAnnotationArgumentInfo> modeled = new LinkedHashMap<>();
arguments.forEach((key, arg) -> modeled.put(key, createArgument(arg, factory)));
return modeled;
}
private static class KotlinAnnotationClassValueInfo extends KotlinAnnotationArgumentInfo {
private final KotlinTypeReference value;
private KotlinAnnotationClassValueInfo(KotlinTypeReference value) {
this.value = value;
}
private static KotlinAnnotationClassValueInfo create(KClassValue arg, DexItemFactory factory) {
return new KotlinAnnotationClassValueInfo(
KotlinTypeReference.fromBinaryName(arg.getValue(), factory));
}
@Override
public void trace(DexDefinitionSupplier definitionSupplier) {
value.trace(definitionSupplier);
}
@Override
boolean rewrite(
Consumer<KmAnnotationArgument<?>> consumer, AppView<?> appView, NamingLens namingLens) {
return value.toRenamedBinaryNameOrDefault(
rewrittenValue -> consumer.accept(new KClassValue(rewrittenValue)),
appView,
namingLens,
ClassClassifiers.anyName);
}
}
private static class KotlinAnnotationEnumValueInfo extends KotlinAnnotationArgumentInfo {
private final KotlinTypeReference enumClassName;
private final String enumEntryName;
private KotlinAnnotationEnumValueInfo(KotlinTypeReference enumClassName, String enumEntryName) {
this.enumClassName = enumClassName;
this.enumEntryName = enumEntryName;
}
private static KotlinAnnotationEnumValueInfo create(EnumValue arg, DexItemFactory factory) {
return new KotlinAnnotationEnumValueInfo(
KotlinTypeReference.fromBinaryName(arg.getEnumClassName(), factory),
arg.getEnumEntryName());
}
@Override
public void trace(DexDefinitionSupplier definitionSupplier) {
enumClassName.trace(definitionSupplier);
}
@Override
boolean rewrite(
Consumer<KmAnnotationArgument<?>> consumer, AppView<?> appView, NamingLens namingLens) {
return enumClassName.toRenamedBinaryNameOrDefault(
rewrittenEnumClassName ->
consumer.accept(new EnumValue(rewrittenEnumClassName, enumEntryName)),
appView,
namingLens,
ClassClassifiers.anyName);
}
}
private static class KotlinAnnotationAnnotationValueInfo extends KotlinAnnotationArgumentInfo {
private final KotlinAnnotationInfo value;
private KotlinAnnotationAnnotationValueInfo(KotlinAnnotationInfo value) {
this.value = value;
}
private static KotlinAnnotationAnnotationValueInfo create(
AnnotationValue arg, DexItemFactory factory) {
return new KotlinAnnotationAnnotationValueInfo(
KotlinAnnotationInfo.create(arg.getValue(), factory));
}
@Override
public void trace(DexDefinitionSupplier definitionSupplier) {
value.trace(definitionSupplier);
}
@Override
boolean rewrite(
Consumer<KmAnnotationArgument<?>> consumer, AppView<?> appView, NamingLens namingLens) {
return value.rewrite(
rewrittenAnnotation -> {
if (rewrittenAnnotation != null) {
consumer.accept(new AnnotationValue(rewrittenAnnotation));
}
},
appView,
namingLens);
}
}
private static class KotlinAnnotationArrayValueInfo extends KotlinAnnotationArgumentInfo {
private static final KotlinAnnotationArrayValueInfo EMPTY =
new KotlinAnnotationArrayValueInfo(ImmutableList.of());
private final List<KotlinAnnotationArgumentInfo> value;
private KotlinAnnotationArrayValueInfo(List<KotlinAnnotationArgumentInfo> value) {
this.value = value;
}
private static KotlinAnnotationArrayValueInfo create(ArrayValue arg, DexItemFactory factory) {
if (arg.getValue().isEmpty()) {
return EMPTY;
}
ImmutableList.Builder<KotlinAnnotationArgumentInfo> builder = ImmutableList.builder();
for (KmAnnotationArgument<?> argument : arg.getValue()) {
builder.add(createArgument(argument, factory));
}
return new KotlinAnnotationArrayValueInfo(builder.build());
}
@Override
public void trace(DexDefinitionSupplier definitionSupplier) {
for (KotlinAnnotationArgumentInfo kotlinAnnotationArgumentInfo : value) {
kotlinAnnotationArgumentInfo.trace(definitionSupplier);
}
}
@Override
boolean rewrite(
Consumer<KmAnnotationArgument<?>> consumer, AppView<?> appView, NamingLens namingLens) {
List<KmAnnotationArgument<?>> rewrittenArguments = new ArrayList<>();
boolean rewritten = false;
for (KotlinAnnotationArgumentInfo kotlinAnnotationArgumentInfo : value) {
rewritten |=
kotlinAnnotationArgumentInfo.rewrite(
rewrittenArg -> {
if (rewrittenArg != null) {
rewrittenArguments.add(rewrittenArg);
}
},
appView,
namingLens);
}
consumer.accept(new ArrayValue(rewrittenArguments));
return rewritten;
}
}
private static class KotlinAnnotationPrimitiveArgumentInfo extends KotlinAnnotationArgumentInfo {
private final KmAnnotationArgument<?> argument;
private KotlinAnnotationPrimitiveArgumentInfo(KmAnnotationArgument<?> argument) {
this.argument = argument;
}
private static KotlinAnnotationPrimitiveArgumentInfo create(KmAnnotationArgument<?> argument) {
return new KotlinAnnotationPrimitiveArgumentInfo(argument);
}
@Override
public void trace(DexDefinitionSupplier definitionSupplier) {
// Nothing to trace
}
@Override
boolean rewrite(
Consumer<KmAnnotationArgument<?>> consumer, AppView<?> appView, NamingLens namingLens) {
consumer.accept(argument);
return false;
}
}
}