diff --git a/.idea/artifacts/KotlinPlugin.xml b/.idea/artifacts/KotlinPlugin.xml index 79ada566ed9..cfd98e040c7 100644 --- a/.idea/artifacts/KotlinPlugin.xml +++ b/.idea/artifacts/KotlinPlugin.xml @@ -72,6 +72,7 @@ + diff --git a/build.xml b/build.xml index 3040972d801..ed1d3d9ef2e 100644 --- a/build.xml +++ b/build.xml @@ -653,9 +653,11 @@ + + diff --git a/plugins/android-extensions/android-extensions-compiler/android-extensions-compiler.iml b/plugins/android-extensions/android-extensions-compiler/android-extensions-compiler.iml index 70f7dd7cc64..a1b321e4270 100644 --- a/plugins/android-extensions/android-extensions-compiler/android-extensions-compiler.iml +++ b/plugins/android-extensions/android-extensions-compiler/android-extensions-compiler.iml @@ -13,5 +13,6 @@ + \ No newline at end of file diff --git a/plugins/android-extensions/android-extensions-compiler/src/org/jetbrains/kotlin/android/synthetic/codegen/AndroidClassType.kt b/plugins/android-extensions/android-extensions-compiler/src/org/jetbrains/kotlin/android/synthetic/codegen/AndroidContainerType.kt similarity index 61% rename from plugins/android-extensions/android-extensions-compiler/src/org/jetbrains/kotlin/android/synthetic/codegen/AndroidClassType.kt rename to plugins/android-extensions/android-extensions-compiler/src/org/jetbrains/kotlin/android/synthetic/codegen/AndroidContainerType.kt index e4c27ca0e82..9fd233e82ee 100644 --- a/plugins/android-extensions/android-extensions-compiler/src/org/jetbrains/kotlin/android/synthetic/codegen/AndroidClassType.kt +++ b/plugins/android-extensions/android-extensions-compiler/src/org/jetbrains/kotlin/android/synthetic/codegen/AndroidContainerType.kt @@ -22,26 +22,26 @@ import org.jetbrains.kotlin.load.java.lazy.descriptors.LazyJavaClassDescriptor import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.resolve.lazy.descriptors.LazyClassDescriptor -enum class AndroidClassType(className: String, val supportsCache: Boolean = false, val fragment: Boolean = false) { - ACTIVITY(AndroidConst.ACTIVITY_FQNAME, supportsCache = true), - FRAGMENT(AndroidConst.FRAGMENT_FQNAME, supportsCache = true, fragment = true), - DIALOG(AndroidConst.DIALOG_FQNAME, supportsCache = false), - SUPPORT_FRAGMENT_ACTIVITY(AndroidConst.SUPPORT_FRAGMENT_ACTIVITY_FQNAME, supportsCache = true), - SUPPORT_FRAGMENT(AndroidConst.SUPPORT_FRAGMENT_FQNAME, supportsCache = true, fragment = true), - VIEW(AndroidConst.VIEW_FQNAME, supportsCache = true), +enum class AndroidContainerType(className: String, val doesSupportCache: Boolean = false, val isFragment: Boolean = false) { + ACTIVITY(AndroidConst.ACTIVITY_FQNAME, doesSupportCache = true), + FRAGMENT(AndroidConst.FRAGMENT_FQNAME, doesSupportCache = true, isFragment = true), + DIALOG(AndroidConst.DIALOG_FQNAME, doesSupportCache = false), + SUPPORT_FRAGMENT_ACTIVITY(AndroidConst.SUPPORT_FRAGMENT_ACTIVITY_FQNAME, doesSupportCache = true), + SUPPORT_FRAGMENT(AndroidConst.SUPPORT_FRAGMENT_FQNAME, doesSupportCache = true, isFragment = true), + VIEW(AndroidConst.VIEW_FQNAME, doesSupportCache = true), UNKNOWN(""); val internalClassName: String = className.replace('.', '/') companion object { - fun getClassType(descriptor: ClassifierDescriptor): AndroidClassType { - fun getClassTypeInternal(name: String): AndroidClassType? = when (name) { - AndroidConst.ACTIVITY_FQNAME -> AndroidClassType.ACTIVITY - AndroidConst.FRAGMENT_FQNAME -> AndroidClassType.FRAGMENT - AndroidConst.DIALOG_FQNAME -> AndroidClassType.DIALOG - AndroidConst.SUPPORT_FRAGMENT_ACTIVITY_FQNAME -> AndroidClassType.SUPPORT_FRAGMENT_ACTIVITY - AndroidConst.SUPPORT_FRAGMENT_FQNAME -> AndroidClassType.SUPPORT_FRAGMENT - AndroidConst.VIEW_FQNAME -> AndroidClassType.VIEW + fun get(descriptor: ClassifierDescriptor): AndroidContainerType { + fun getClassTypeInternal(name: String): AndroidContainerType? = when (name) { + AndroidConst.ACTIVITY_FQNAME -> AndroidContainerType.ACTIVITY + AndroidConst.FRAGMENT_FQNAME -> AndroidContainerType.FRAGMENT + AndroidConst.DIALOG_FQNAME -> AndroidContainerType.DIALOG + AndroidConst.SUPPORT_FRAGMENT_ACTIVITY_FQNAME -> AndroidContainerType.SUPPORT_FRAGMENT_ACTIVITY + AndroidConst.SUPPORT_FRAGMENT_FQNAME -> AndroidContainerType.SUPPORT_FRAGMENT + AndroidConst.VIEW_FQNAME -> AndroidContainerType.VIEW else -> null } @@ -57,12 +57,12 @@ enum class AndroidClassType(className: String, val supportsCache: Boolean = fals for (supertype in descriptor.typeConstructor.supertypes) { val declarationDescriptor = supertype.constructor.declarationDescriptor if (declarationDescriptor != null) { - val androidClassType = getClassType(declarationDescriptor) - if (androidClassType != AndroidClassType.UNKNOWN) return androidClassType + val androidClassType = get(declarationDescriptor) + if (androidClassType != AndroidContainerType.UNKNOWN) return androidClassType } } - return AndroidClassType.UNKNOWN + return AndroidContainerType.UNKNOWN } } } \ No newline at end of file diff --git a/plugins/android-extensions/android-extensions-compiler/src/org/jetbrains/kotlin/android/synthetic/codegen/AndroidExpressionCodegenExtension.kt b/plugins/android-extensions/android-extensions-compiler/src/org/jetbrains/kotlin/android/synthetic/codegen/AndroidExpressionCodegenExtension.kt index b4348e6b1f9..806468836ad 100644 --- a/plugins/android-extensions/android-extensions-compiler/src/org/jetbrains/kotlin/android/synthetic/codegen/AndroidExpressionCodegenExtension.kt +++ b/plugins/android-extensions/android-extensions-compiler/src/org/jetbrains/kotlin/android/synthetic/codegen/AndroidExpressionCodegenExtension.kt @@ -16,7 +16,9 @@ package org.jetbrains.kotlin.android.synthetic.codegen +import kotlinx.android.extensions.CacheImplementation.NO_CACHE import org.jetbrains.kotlin.android.synthetic.AndroidConst +import org.jetbrains.kotlin.android.synthetic.descriptors.ContainerOptionsProxy import org.jetbrains.kotlin.android.synthetic.descriptors.AndroidSyntheticPackageFragmentDescriptor import org.jetbrains.kotlin.android.synthetic.res.AndroidSyntheticFunction import org.jetbrains.kotlin.android.synthetic.res.AndroidSyntheticProperty @@ -33,7 +35,6 @@ import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassOrAny import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue -import org.jetbrains.kotlin.resolve.source.KotlinSourceElement import org.jetbrains.org.objectweb.asm.Label import org.jetbrains.org.objectweb.asm.Opcodes.ACC_PRIVATE import org.jetbrains.org.objectweb.asm.Opcodes.ACC_PUBLIC @@ -48,15 +49,7 @@ class AndroidExpressionCodegenExtension : ExpressionCodegenExtension { val CLEAR_CACHE_METHOD_NAME = "_\$_clearFindViewByIdCache" val ON_DESTROY_METHOD_NAME = "onDestroyView" - fun doesContainerSupportCache(container: ClassDescriptor): Boolean { - return container.source is KotlinSourceElement - } - - fun shouldCacheResource(container: ClassDescriptor, resource: PropertyDescriptor): Boolean { - if (!doesContainerSupportCache(container)) { - return false - } - + fun shouldCacheResource(resource: PropertyDescriptor): Boolean { return (resource as? AndroidSyntheticProperty)?.shouldBeCached ?: false } } @@ -66,7 +59,7 @@ class AndroidExpressionCodegenExtension : ExpressionCodegenExtension { val state: GenerationState, val descriptor: ClassDescriptor, val classOrObject: KtClassOrObject, - val androidClassType: AndroidClassType) + val containerOptions: ContainerOptionsProxy) override fun applyProperty(receiver: StackValue, resolvedCall: ResolvedCall<*>, c: ExpressionCodegenExtension.Context): StackValue? { val resultingDescriptor = resolvedCall.resultingDescriptor @@ -94,12 +87,14 @@ class AndroidExpressionCodegenExtension : ExpressionCodegenExtension { container: ClassDescriptor, c: ExpressionCodegenExtension.Context ): StackValue? { - if (!doesContainerSupportCache(container)) { + val containerOptions = ContainerOptionsProxy.get(container) + + if (!containerOptions.cache.hasCache) { return StackValue.functionCall(Type.VOID_TYPE) {} } - val androidClassType = AndroidClassType.getClassType(container) - if (androidClassType == AndroidClassType.UNKNOWN) return null + val androidClassType = AndroidContainerType.get(container) + if (androidClassType == AndroidContainerType.UNKNOWN) return null return StackValue.functionCall(Type.VOID_TYPE) { val bytecodeClassName = c.typeMapper.mapType(container).internalName @@ -113,15 +108,15 @@ class AndroidExpressionCodegenExtension : ExpressionCodegenExtension { receiver: StackValue, resolvedCall: ResolvedCall<*>, c: ExpressionCodegenExtension.Context, - descriptor: PropertyDescriptor + resource: PropertyDescriptor ): StackValue? { - if (descriptor !is AndroidSyntheticProperty) return null - val packageFragment = descriptor.containingDeclaration as? AndroidSyntheticPackageFragmentDescriptor ?: return null + if (resource !is AndroidSyntheticProperty) return null + val packageFragment = resource.containingDeclaration as? AndroidSyntheticPackageFragmentDescriptor ?: return null val androidPackage = packageFragment.packageData.moduleData.module.applicationPackage - val receiverDescriptor = resolvedCall.getReceiverDeclarationDescriptor() as? ClassDescriptor ?: return null - val androidClassType = AndroidClassType.getClassType(receiverDescriptor) + val container = resolvedCall.getReceiverDeclarationDescriptor() as? ClassDescriptor ?: return null - return ResourcePropertyStackValue(receiver, c.typeMapper, descriptor, receiverDescriptor, androidClassType, androidPackage) + val containerOptions = ContainerOptionsProxy.get(container) + return ResourcePropertyStackValue(receiver, c.typeMapper, resource, container, containerOptions, androidPackage) } private fun ResolvedCall<*>.getReceiverDeclarationDescriptor(): ClassifierDescriptor? { @@ -132,19 +127,18 @@ class AndroidExpressionCodegenExtension : ExpressionCodegenExtension { val classBuilder = codegen.v val targetClass = codegen.myClass as? KtClassOrObject ?: return - val descriptor = codegen.descriptor - if (descriptor.kind != ClassKind.CLASS || descriptor.isInner || DescriptorUtils.isLocal(descriptor)) return + val container = codegen.descriptor + if (container.kind != ClassKind.CLASS || container.isInner || DescriptorUtils.isLocal(container)) return - // Do not generate anything if class is not supported - val androidClassType = AndroidClassType.getClassType(descriptor) - if (androidClassType == AndroidClassType.UNKNOWN) return + val containerOptions = ContainerOptionsProxy.get(container) + if (containerOptions.cache == NO_CACHE) return - val context = SyntheticPartsGenerateContext(classBuilder, codegen.state, descriptor, targetClass, androidClassType) + val context = SyntheticPartsGenerateContext(classBuilder, codegen.state, container, targetClass, containerOptions) context.generateCachedFindViewByIdFunction() context.generateClearCacheFunction() - if (androidClassType.fragment) { - val classMembers = descriptor.unsubstitutedMemberScope.getContributedDescriptors() + if (containerOptions.classType.isFragment) { + val classMembers = container.unsubstitutedMemberScope.getContributedDescriptors() val onDestroy = classMembers.firstOrNull { it is FunctionDescriptor && it.isOnDestroyFunction() } if (onDestroy == null) { context.generateOnDestroyFunctionForFragment() @@ -249,12 +243,12 @@ class AndroidExpressionCodegenExtension : ExpressionCodegenExtension { // Resolve View via findViewById if not in cache iv.load(0, classType) - when (androidClassType) { - AndroidClassType.ACTIVITY, AndroidClassType.SUPPORT_FRAGMENT_ACTIVITY, AndroidClassType.VIEW, AndroidClassType.DIALOG -> { + when (containerOptions.classType) { + AndroidContainerType.ACTIVITY, AndroidContainerType.SUPPORT_FRAGMENT_ACTIVITY, AndroidContainerType.VIEW, AndroidContainerType.DIALOG -> { loadId() iv.invokevirtual(className, "findViewById", "(I)Landroid/view/View;", false) } - AndroidClassType.FRAGMENT, AndroidClassType.SUPPORT_FRAGMENT -> { + AndroidContainerType.FRAGMENT, AndroidContainerType.SUPPORT_FRAGMENT -> { iv.invokevirtual(className, "getView", "()Landroid/view/View;", false) iv.dup() val lgetViewNotNull = Label() @@ -270,7 +264,7 @@ class AndroidExpressionCodegenExtension : ExpressionCodegenExtension { loadId() iv.invokevirtual("android/view/View", "findViewById", "(I)Landroid/view/View;", false) } - else -> throw IllegalStateException("Can't generate code for $androidClassType") + else -> throw IllegalStateException("Can't generate code for ${containerOptions.classType}") } iv.store(2, viewType) diff --git a/plugins/android-extensions/android-extensions-compiler/src/org/jetbrains/kotlin/android/synthetic/codegen/AndroidOnDestroyClassBuilderInterceptorExtension.kt b/plugins/android-extensions/android-extensions-compiler/src/org/jetbrains/kotlin/android/synthetic/codegen/AndroidOnDestroyClassBuilderInterceptorExtension.kt index 9216145f7a5..9e190916619 100644 --- a/plugins/android-extensions/android-extensions-compiler/src/org/jetbrains/kotlin/android/synthetic/codegen/AndroidOnDestroyClassBuilderInterceptorExtension.kt +++ b/plugins/android-extensions/android-extensions-compiler/src/org/jetbrains/kotlin/android/synthetic/codegen/AndroidOnDestroyClassBuilderInterceptorExtension.kt @@ -17,6 +17,8 @@ package org.jetbrains.kotlin.android.synthetic.codegen import com.intellij.psi.PsiElement +import kotlinx.android.extensions.CacheImplementation.NO_CACHE +import org.jetbrains.kotlin.android.synthetic.descriptors.ContainerOptionsProxy import org.jetbrains.kotlin.codegen.ClassBuilder import org.jetbrains.kotlin.codegen.ClassBuilderFactory import org.jetbrains.kotlin.codegen.DelegatingClassBuilder @@ -111,9 +113,9 @@ class AndroidOnDestroyClassBuilderInterceptorExtension : ClassBuilderInterceptor val classType = currentClassName?.let { Type.getObjectType(it) } ?: return - val descriptor = bindingContext.get(BindingContext.CLASS, currentClass) ?: return - val androidClassType = AndroidClassType.getClassType(descriptor) - if (!androidClassType.fragment) return + val container = bindingContext.get(BindingContext.CLASS, currentClass) ?: return + val containerOptions = ContainerOptionsProxy.get(container) + if (!containerOptions.classType.isFragment || containerOptions.cache == NO_CACHE) return val iv = InstructionAdapter(this) iv.load(0, classType) diff --git a/plugins/android-extensions/android-extensions-compiler/src/org/jetbrains/kotlin/android/synthetic/codegen/ResourcePropertyStackValue.kt b/plugins/android-extensions/android-extensions-compiler/src/org/jetbrains/kotlin/android/synthetic/codegen/ResourcePropertyStackValue.kt index c1f9228e602..4e1ef01b65f 100644 --- a/plugins/android-extensions/android-extensions-compiler/src/org/jetbrains/kotlin/android/synthetic/codegen/ResourcePropertyStackValue.kt +++ b/plugins/android-extensions/android-extensions-compiler/src/org/jetbrains/kotlin/android/synthetic/codegen/ResourcePropertyStackValue.kt @@ -17,6 +17,8 @@ package org.jetbrains.kotlin.android.synthetic.codegen import org.jetbrains.kotlin.android.synthetic.AndroidConst +import org.jetbrains.kotlin.android.synthetic.codegen.AndroidExpressionCodegenExtension.Companion.shouldCacheResource +import org.jetbrains.kotlin.android.synthetic.descriptors.ContainerOptionsProxy import org.jetbrains.kotlin.android.synthetic.res.AndroidSyntheticProperty import org.jetbrains.kotlin.codegen.StackValue import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper @@ -29,22 +31,23 @@ import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter class ResourcePropertyStackValue( val receiver: StackValue, val typeMapper: KotlinTypeMapper, - val propertyDescriptor: PropertyDescriptor, - val receiverDescriptor: ClassDescriptor, - val androidClassType: AndroidClassType, + val resource: PropertyDescriptor, + val container: ClassDescriptor, + val containerOptions: ContainerOptionsProxy, val androidPackage: String -) : StackValue(typeMapper.mapType(propertyDescriptor.returnType!!)) { +) : StackValue(typeMapper.mapType(resource.returnType!!)) { + private val androidClassType get() = containerOptions.classType override fun putSelector(type: Type, v: InstructionAdapter) { - val returnTypeString = typeMapper.mapType(propertyDescriptor.type.lowerIfFlexible()).className + val returnTypeString = typeMapper.mapType(resource.type.lowerIfFlexible()).className if (AndroidConst.FRAGMENT_FQNAME == returnTypeString || AndroidConst.SUPPORT_FRAGMENT_FQNAME == returnTypeString) { return putSelectorForFragment(v) } - val syntheticProperty = propertyDescriptor as AndroidSyntheticProperty + val syntheticProperty = resource as AndroidSyntheticProperty - if (androidClassType.supportsCache && AndroidExpressionCodegenExtension.shouldCacheResource(receiverDescriptor, propertyDescriptor)) { - val declarationDescriptorType = typeMapper.mapType(receiverDescriptor) + if (containerOptions.cache.hasCache && shouldCacheResource(resource)) { + val declarationDescriptorType = typeMapper.mapType(container) receiver.put(declarationDescriptorType, v) val resourceId = syntheticProperty.resource.id @@ -55,12 +58,12 @@ class ResourcePropertyStackValue( } else { when (androidClassType) { - AndroidClassType.ACTIVITY, AndroidClassType.SUPPORT_FRAGMENT_ACTIVITY, AndroidClassType.VIEW, AndroidClassType.DIALOG -> { + AndroidContainerType.ACTIVITY, AndroidContainerType.SUPPORT_FRAGMENT_ACTIVITY, AndroidContainerType.VIEW, AndroidContainerType.DIALOG -> { receiver.put(Type.getType("L${androidClassType.internalClassName};"), v) getResourceId(v) v.invokevirtual(androidClassType.internalClassName, "findViewById", "(I)Landroid/view/View;", false) } - AndroidClassType.FRAGMENT, AndroidClassType.SUPPORT_FRAGMENT -> { + AndroidContainerType.FRAGMENT, AndroidContainerType.SUPPORT_FRAGMENT -> { receiver.put(Type.getType("L${androidClassType.internalClassName};"), v) v.invokevirtual(androidClassType.internalClassName, "getView", "()Landroid/view/View;", false) getResourceId(v) @@ -77,17 +80,17 @@ class ResourcePropertyStackValue( receiver.put(Type.getType("L${androidClassType.internalClassName};"), v) when (androidClassType) { - AndroidClassType.ACTIVITY, AndroidClassType.FRAGMENT -> { + AndroidContainerType.ACTIVITY, AndroidContainerType.FRAGMENT -> { v.invokevirtual(androidClassType.internalClassName, "getFragmentManager", "()Landroid/app/FragmentManager;", false) getResourceId(v) v.invokevirtual("android/app/FragmentManager", "findFragmentById", "(I)Landroid/app/Fragment;", false) } - AndroidClassType.SUPPORT_FRAGMENT -> { + AndroidContainerType.SUPPORT_FRAGMENT -> { v.invokevirtual(androidClassType.internalClassName, "getFragmentManager", "()Landroid/support/v4/app/FragmentManager;", false) getResourceId(v) v.invokevirtual("android/support/v4/app/FragmentManager", "findFragmentById", "(I)Landroid/support/v4/app/Fragment;", false) } - AndroidClassType.SUPPORT_FRAGMENT_ACTIVITY -> { + AndroidContainerType.SUPPORT_FRAGMENT_ACTIVITY -> { v.invokevirtual(androidClassType.internalClassName, "getSupportFragmentManager", "()Landroid/support/v4/app/FragmentManager;", false) getResourceId(v) v.invokevirtual("android/support/v4/app/FragmentManager", "findFragmentById", "(I)Landroid/support/v4/app/Fragment;", false) @@ -99,6 +102,6 @@ class ResourcePropertyStackValue( } fun getResourceId(v: InstructionAdapter) { - v.getstatic(androidPackage.replace(".", "/") + "/R\$id", propertyDescriptor.name.asString(), "I") + v.getstatic(androidPackage.replace(".", "/") + "/R\$id", resource.name.asString(), "I") } } \ No newline at end of file diff --git a/plugins/android-extensions/android-extensions-compiler/src/org/jetbrains/kotlin/android/synthetic/descriptors/ContainerOptionsProxy.kt b/plugins/android-extensions/android-extensions-compiler/src/org/jetbrains/kotlin/android/synthetic/descriptors/ContainerOptionsProxy.kt new file mode 100644 index 00000000000..3fa857b4efe --- /dev/null +++ b/plugins/android-extensions/android-extensions-compiler/src/org/jetbrains/kotlin/android/synthetic/descriptors/ContainerOptionsProxy.kt @@ -0,0 +1,67 @@ +/* + * Copyright 2010-2017 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.kotlin.android.synthetic.descriptors + +import org.jetbrains.kotlin.resolve.constants.ConstantValue +import kotlinx.android.extensions.CacheImplementation +import kotlinx.android.extensions.CacheImplementation.* +import kotlinx.android.extensions.ContainerOptions +import org.jetbrains.kotlin.android.synthetic.codegen.AndroidContainerType +import org.jetbrains.kotlin.descriptors.ClassDescriptor +import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor +import org.jetbrains.kotlin.name.FqName +import org.jetbrains.kotlin.resolve.constants.EnumValue +import org.jetbrains.kotlin.resolve.source.KotlinSourceElement + +class ContainerOptionsProxy(val classType: AndroidContainerType, val cache: CacheImplementation) { + companion object { + private val CONTAINER_OPTIONS_FQNAME = FqName(ContainerOptions::class.java.canonicalName) + private val CACHE_NAME = ContainerOptions::cache.name + + private val DEFAULT_CACHE_IMPL = HASH_MAP + + fun get(container: ClassDescriptor): ContainerOptionsProxy { + val classType = AndroidContainerType.get(container) + + val anno = container.annotations.findAnnotation(CONTAINER_OPTIONS_FQNAME) + + if (anno == null) { + // Java classes (and Kotlin classes from other modules) does not support cache by default + val supportsCache = container.source is KotlinSourceElement && classType.doesSupportCache + return ContainerOptionsProxy(classType, if (supportsCache) DEFAULT_CACHE_IMPL else NO_CACHE) + } + + val cache = anno.getEnumValue(CACHE_NAME, HASH_MAP) { valueOf(it) } + + return ContainerOptionsProxy(classType, cache) + } + } +} + +private operator fun AnnotationDescriptor.get(name: String): ConstantValue<*>? { + return allValueArguments.entries.firstOrNull { it.key.name.asString() == name }?.value +} + +private fun > AnnotationDescriptor.getEnumValue(name: String, defaultValue: E, factory: (String) -> E): E { + val valueName = (this[name] as? EnumValue)?.value?.name?.asString() ?: defaultValue.name + + return try { + factory(valueName) + } catch (e: Exception) { + defaultValue + } +} \ No newline at end of file diff --git a/plugins/android-extensions/android-extensions-compiler/testData/codegen/bytecodeShape/activityWithEntityOptionsNoCache/activityWithEntityOptionsNoCache.kt b/plugins/android-extensions/android-extensions-compiler/testData/codegen/bytecodeShape/activityWithEntityOptionsNoCache/activityWithEntityOptionsNoCache.kt new file mode 100644 index 00000000000..20698917346 --- /dev/null +++ b/plugins/android-extensions/android-extensions-compiler/testData/codegen/bytecodeShape/activityWithEntityOptionsNoCache/activityWithEntityOptionsNoCache.kt @@ -0,0 +1,19 @@ +package test + +import android.app.Activity +import android.os.Bundle +import java.io.File +import kotlinx.android.synthetic.main.layout.* +import kotlinx.android.extensions.* + +@ContainerOptions(cache = CacheImplementation.NO_CACHE) +public class MyActivity : Activity() { + init {login} +} + +// 0 public _\$_findCachedViewById +// 0 public _\$_clearFindViewByIdCache +// 1 GETSTATIC test/R\$id\.login +// 0 INVOKEVIRTUAL test/MyActivity\._\$_findCachedViewById +// 1 INVOKEVIRTUAL android/app/Activity\.findViewById +// 1 CHECKCAST android/widget/Button \ No newline at end of file diff --git a/plugins/android-extensions/android-extensions-compiler/testData/codegen/bytecodeShape/activityWithEntityOptionsNoCache/res/layout/layout.xml b/plugins/android-extensions/android-extensions-compiler/testData/codegen/bytecodeShape/activityWithEntityOptionsNoCache/res/layout/layout.xml new file mode 100644 index 00000000000..4d73173b521 --- /dev/null +++ b/plugins/android-extensions/android-extensions-compiler/testData/codegen/bytecodeShape/activityWithEntityOptionsNoCache/res/layout/layout.xml @@ -0,0 +1,17 @@ + + + + +