| // Copyright (c) 2018, 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.naming.MemberNaming; | |
| import com.google.common.collect.ImmutableList; | |
| import com.google.common.collect.Maps; | |
| import java.util.Collections; | |
| import java.util.List; | |
| import java.util.Map; | |
| /** | |
| * Represents the definition of a Kotlin class. | |
| * | |
| * <p>See https://kotlinlang.org/docs/reference/classes.html</p> | |
| */ | |
| public class TestKotlinClass { | |
| /** | |
| * This is the suffix appended by Kotlin compiler to getter and setter method names of | |
| * internal properties. | |
| * | |
| * It must match the string passed in command-line option "-module-name" of Kotlin compiler. The | |
| * default value is "main". | |
| */ | |
| private static final String KOTLIN_MODULE_NAME = "main"; | |
| enum Visibility { | |
| PUBLIC, | |
| INTERNAL, | |
| PROTECTED, | |
| PRIVATE; | |
| } | |
| enum AccessorKind { | |
| FROM_COMPANION("cp"), | |
| FROM_INNER("p"), | |
| FROM_LAMBDA("lp"); | |
| private final String accessorSuffix; | |
| AccessorKind(String accessorSuffix) { | |
| this.accessorSuffix = accessorSuffix; | |
| } | |
| public String getAccessorSuffix() { | |
| return accessorSuffix; | |
| } | |
| } | |
| protected static class KotlinProperty { | |
| private final String name; | |
| private final String type; | |
| private final Visibility visibility; | |
| private final int index; | |
| private KotlinProperty(String name, String type, Visibility visibility, int index) { | |
| this.name = name; | |
| this.type = type; | |
| this.index = index; | |
| this.visibility = visibility; | |
| } | |
| public String getName() { | |
| return name; | |
| } | |
| public String getType() { | |
| return type; | |
| } | |
| public Visibility getVisibility() { | |
| return visibility; | |
| } | |
| public int getIndex() { | |
| return index; | |
| } | |
| } | |
| protected final String className; | |
| protected final Map<String, KotlinProperty> properties = Maps.newHashMap(); | |
| public TestKotlinClass(String className) { | |
| this.className = className; | |
| } | |
| public String getClassName() { | |
| return className; | |
| } | |
| public TestKotlinClass addProperty(String name, String type, Visibility visibility) { | |
| assert !properties.containsKey(name); | |
| properties.put(name, new KotlinProperty(name, type, visibility, properties.size())); | |
| return this; | |
| } | |
| protected KotlinProperty getProperty(String name) { | |
| assert properties.containsKey(name); | |
| return properties.get(name); | |
| } | |
| public MemberNaming.MethodSignature getGetterForProperty(String propertyName) { | |
| KotlinProperty property = getProperty(propertyName); | |
| return getGetterForProperty(property, property.getVisibility() == Visibility.INTERNAL); | |
| } | |
| public MemberNaming.MethodSignature getSetterForProperty(String propertyName) { | |
| KotlinProperty property = getProperty(propertyName); | |
| return getSetterForProperty(property, property.getVisibility() == Visibility.INTERNAL); | |
| } | |
| public MemberNaming.MethodSignature getGetterAccessorForProperty(String propertyName, | |
| AccessorKind accessorKind) { | |
| KotlinProperty property = getProperty(propertyName); | |
| String getterName = computeGetterName(propertyName); | |
| // Unlike normal getter, module name is not appended for accessor method of internal property. | |
| getterName = wrapWithAccessorPrefixAndSuffix(accessorKind, getterName); | |
| List<String> argumentTypes; | |
| if (accessorKind != AccessorKind.FROM_COMPANION) { | |
| argumentTypes = ImmutableList.of(getClassName()); | |
| } else { | |
| argumentTypes = ImmutableList.of(); | |
| } | |
| return new MemberNaming.MethodSignature(getterName, property.type, argumentTypes); | |
| } | |
| public MemberNaming.MethodSignature getSetterAccessorForProperty(String propertyName, | |
| AccessorKind accessorKind) { | |
| KotlinProperty property = getProperty(propertyName); | |
| String setterName = computeSetterName(propertyName); | |
| // Unlike normal setter, module name is not appended for accessor method of internal property. | |
| setterName = wrapWithAccessorPrefixAndSuffix(accessorKind, setterName); | |
| List<String> argumentTypes; | |
| if (accessorKind != AccessorKind.FROM_COMPANION) { | |
| argumentTypes = ImmutableList.of(getClassName(), property.getType()); | |
| } else { | |
| argumentTypes = ImmutableList.of(property.getType()); | |
| } | |
| return new MemberNaming.MethodSignature(setterName, "void", argumentTypes); | |
| } | |
| protected final MemberNaming.MethodSignature getGetterForProperty(KotlinProperty property, | |
| boolean applyMangling) { | |
| String type = property.type; | |
| String getterName = computeGetterName(property.name); | |
| if (applyMangling) { | |
| getterName = appendInternalSuffix(getterName); | |
| } | |
| return new MemberNaming.MethodSignature(getterName, type, Collections.emptyList()); | |
| } | |
| protected final MemberNaming.MethodSignature getSetterForProperty(KotlinProperty property, | |
| boolean applyMangling) { | |
| String setterName = computeSetterName(property.name); | |
| if (applyMangling) { | |
| setterName = appendInternalSuffix(setterName); | |
| } | |
| return new MemberNaming.MethodSignature(setterName, "void", | |
| Collections.singleton(property.getType())); | |
| } | |
| private static String computeGetterName(String propertyName) { | |
| if (propertyName.length() > 2 && propertyName.startsWith("is") | |
| && (propertyName.charAt(2) == '_' || Character.isUpperCase(propertyName.charAt(2)))) { | |
| // Getter for property "isAbc" is "isAbc". | |
| return propertyName; | |
| } else { | |
| // Getter for property "abc" is "getAbc". | |
| return "get" + Character.toUpperCase(propertyName.charAt(0)) + propertyName.substring(1); | |
| } | |
| } | |
| private static String computeSetterName(String propertyName) { | |
| return "set" + Character.toUpperCase(propertyName.charAt(0)) + propertyName.substring(1); | |
| } | |
| private static String appendInternalSuffix(String name) { | |
| return name + "$" + KOTLIN_MODULE_NAME; | |
| } | |
| private String wrapWithAccessorPrefixAndSuffix(AccessorKind accessorKind, String methodName) { | |
| return "access$" + methodName + "$" + accessorKind.getAccessorSuffix(); | |
| } | |
| } |