|  | // 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; | 
|  | } | 
|  | } | 
|  | } |