Android Extensions: Add global cache flag in compiler plugin
This commit is contained in:
@@ -74,7 +74,7 @@
|
|||||||
<expressionCodegenExtension implementation="org.jetbrains.kotlin.android.synthetic.idea.IDEAndroidExtensionsExpressionCodegenExtension"/>
|
<expressionCodegenExtension implementation="org.jetbrains.kotlin.android.synthetic.idea.IDEAndroidExtensionsExpressionCodegenExtension"/>
|
||||||
<defaultErrorMessages implementation="org.jetbrains.kotlin.android.synthetic.diagnostic.DefaultErrorMessagesAndroid"/>
|
<defaultErrorMessages implementation="org.jetbrains.kotlin.android.synthetic.diagnostic.DefaultErrorMessagesAndroid"/>
|
||||||
<storageComponentContainerContributor implementation="org.jetbrains.kotlin.android.synthetic.AndroidExtensionPropertiesComponentContainerContributor"/>
|
<storageComponentContainerContributor implementation="org.jetbrains.kotlin.android.synthetic.AndroidExtensionPropertiesComponentContainerContributor"/>
|
||||||
<classBuilderFactoryInterceptorExtension implementation="org.jetbrains.kotlin.android.synthetic.codegen.AndroidOnDestroyClassBuilderInterceptorExtension"/>
|
<classBuilderFactoryInterceptorExtension implementation="org.jetbrains.kotlin.android.synthetic.idea.IDEAndroidOnDestroyClassBuilderInterceptorExtension"/>
|
||||||
<packageFragmentProviderExtension implementation="org.jetbrains.kotlin.android.synthetic.idea.res.IDEAndroidPackageFragmentProviderExtension"/>
|
<packageFragmentProviderExtension implementation="org.jetbrains.kotlin.android.synthetic.idea.res.IDEAndroidPackageFragmentProviderExtension"/>
|
||||||
<simpleNameReferenceExtension implementation="org.jetbrains.kotlin.android.synthetic.idea.AndroidSimpleNameReferenceExtension"/>
|
<simpleNameReferenceExtension implementation="org.jetbrains.kotlin.android.synthetic.idea.AndroidSimpleNameReferenceExtension"/>
|
||||||
<kotlinIndicesHelperExtension implementation="org.jetbrains.kotlin.android.synthetic.idea.AndroidIndicesHelperExtension"/>
|
<kotlinIndicesHelperExtension implementation="org.jetbrains.kotlin.android.synthetic.idea.AndroidIndicesHelperExtension"/>
|
||||||
|
|||||||
+23
-10
@@ -19,11 +19,12 @@ package org.jetbrains.kotlin.android.synthetic
|
|||||||
import com.intellij.mock.MockProject
|
import com.intellij.mock.MockProject
|
||||||
import com.intellij.openapi.extensions.Extensions
|
import com.intellij.openapi.extensions.Extensions
|
||||||
import com.intellij.openapi.project.Project
|
import com.intellij.openapi.project.Project
|
||||||
|
import kotlinx.android.extensions.CacheImplementation
|
||||||
import org.jetbrains.kotlin.android.parcel.ParcelableCodegenExtension
|
import org.jetbrains.kotlin.android.parcel.ParcelableCodegenExtension
|
||||||
import org.jetbrains.kotlin.android.parcel.ParcelableDeclarationChecker
|
import org.jetbrains.kotlin.android.parcel.ParcelableDeclarationChecker
|
||||||
import org.jetbrains.kotlin.android.parcel.ParcelableResolveExtension
|
import org.jetbrains.kotlin.android.parcel.ParcelableResolveExtension
|
||||||
import org.jetbrains.kotlin.android.synthetic.codegen.AndroidOnDestroyClassBuilderInterceptorExtension
|
|
||||||
import org.jetbrains.kotlin.android.synthetic.codegen.CliAndroidExtensionsExpressionCodegenExtension
|
import org.jetbrains.kotlin.android.synthetic.codegen.CliAndroidExtensionsExpressionCodegenExtension
|
||||||
|
import org.jetbrains.kotlin.android.synthetic.codegen.CliAndroidOnDestroyClassBuilderInterceptorExtension
|
||||||
import org.jetbrains.kotlin.android.synthetic.diagnostic.AndroidExtensionPropertiesCallChecker
|
import org.jetbrains.kotlin.android.synthetic.diagnostic.AndroidExtensionPropertiesCallChecker
|
||||||
import org.jetbrains.kotlin.android.synthetic.diagnostic.DefaultErrorMessagesAndroid
|
import org.jetbrains.kotlin.android.synthetic.diagnostic.DefaultErrorMessagesAndroid
|
||||||
import org.jetbrains.kotlin.android.synthetic.res.AndroidLayoutXmlFileManager
|
import org.jetbrains.kotlin.android.synthetic.res.AndroidLayoutXmlFileManager
|
||||||
@@ -49,18 +50,21 @@ import org.jetbrains.kotlin.android.synthetic.codegen.ParcelableClinitClassBuild
|
|||||||
import org.jetbrains.kotlin.resolve.extensions.SyntheticResolveExtension
|
import org.jetbrains.kotlin.resolve.extensions.SyntheticResolveExtension
|
||||||
|
|
||||||
object AndroidConfigurationKeys {
|
object AndroidConfigurationKeys {
|
||||||
val VARIANT: CompilerConfigurationKey<List<String>> = CompilerConfigurationKey.create<List<String>>("Android build variant")
|
val VARIANT = CompilerConfigurationKey.create<List<String>>("Android build variant")
|
||||||
val PACKAGE: CompilerConfigurationKey<String> = CompilerConfigurationKey.create<String>("application package fq name")
|
val PACKAGE = CompilerConfigurationKey.create<String>("application package fq name")
|
||||||
val EXPERIMENTAL: CompilerConfigurationKey<String> = CompilerConfigurationKey.create<String>("enable experimental features")
|
val EXPERIMENTAL = CompilerConfigurationKey.create<String>("enable experimental features")
|
||||||
|
val DEFAULT_CACHE_IMPL = CompilerConfigurationKey.create<String>("default cache implementation")
|
||||||
}
|
}
|
||||||
|
|
||||||
class AndroidCommandLineProcessor : CommandLineProcessor {
|
class AndroidCommandLineProcessor : CommandLineProcessor {
|
||||||
companion object {
|
companion object {
|
||||||
val ANDROID_COMPILER_PLUGIN_ID: String = "org.jetbrains.kotlin.android"
|
val ANDROID_COMPILER_PLUGIN_ID: String = "org.jetbrains.kotlin.android"
|
||||||
|
|
||||||
val VARIANT_OPTION: CliOption = CliOption("variant", "<name;path>", "Android build variant", allowMultipleOccurrences = true)
|
val VARIANT_OPTION = CliOption("variant", "<name;path>", "Android build variant", allowMultipleOccurrences = true)
|
||||||
val PACKAGE_OPTION: CliOption = CliOption("package", "<fq name>", "Application package")
|
val PACKAGE_OPTION = CliOption("package", "<fq name>", "Application package")
|
||||||
val EXPERIMENTAL_OPTION: CliOption = CliOption("experimental", "true/false", "Enable experimental features", required = false)
|
val EXPERIMENTAL_OPTION = CliOption("experimental", "true/false", "Enable experimental features", required = false)
|
||||||
|
val DEFAULT_CACHE_IMPL_OPTION = CliOption(
|
||||||
|
"defaultCacheImplementation", "hashMap/sparseArray/none", "Default cache implementation for module", required = false)
|
||||||
|
|
||||||
/* This option is just for saving Android Extensions status in Kotlin facet. It should not be supported from CLI. */
|
/* This option is just for saving Android Extensions status in Kotlin facet. It should not be supported from CLI. */
|
||||||
val ENABLED_OPTION: CliOption = CliOption("enabled", "true/false", "Enable Android Extensions", required = false)
|
val ENABLED_OPTION: CliOption = CliOption("enabled", "true/false", "Enable Android Extensions", required = false)
|
||||||
@@ -68,13 +72,15 @@ class AndroidCommandLineProcessor : CommandLineProcessor {
|
|||||||
|
|
||||||
override val pluginId: String = ANDROID_COMPILER_PLUGIN_ID
|
override val pluginId: String = ANDROID_COMPILER_PLUGIN_ID
|
||||||
|
|
||||||
override val pluginOptions: Collection<CliOption> = listOf(VARIANT_OPTION, PACKAGE_OPTION, EXPERIMENTAL_OPTION)
|
override val pluginOptions: Collection<CliOption>
|
||||||
|
= listOf(VARIANT_OPTION, PACKAGE_OPTION, EXPERIMENTAL_OPTION, DEFAULT_CACHE_IMPL_OPTION)
|
||||||
|
|
||||||
override fun processOption(option: CliOption, value: String, configuration: CompilerConfiguration) {
|
override fun processOption(option: CliOption, value: String, configuration: CompilerConfiguration) {
|
||||||
when (option) {
|
when (option) {
|
||||||
VARIANT_OPTION -> configuration.appendList(AndroidConfigurationKeys.VARIANT, value)
|
VARIANT_OPTION -> configuration.appendList(AndroidConfigurationKeys.VARIANT, value)
|
||||||
PACKAGE_OPTION -> configuration.put(AndroidConfigurationKeys.PACKAGE, value)
|
PACKAGE_OPTION -> configuration.put(AndroidConfigurationKeys.PACKAGE, value)
|
||||||
EXPERIMENTAL_OPTION -> configuration.put(AndroidConfigurationKeys.EXPERIMENTAL, value)
|
EXPERIMENTAL_OPTION -> configuration.put(AndroidConfigurationKeys.EXPERIMENTAL, value)
|
||||||
|
DEFAULT_CACHE_IMPL_OPTION -> configuration.put(AndroidConfigurationKeys.DEFAULT_CACHE_IMPL, value)
|
||||||
else -> throw CliOptionProcessingException("Unknown option: ${option.name}")
|
else -> throw CliOptionProcessingException("Unknown option: ${option.name}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -87,12 +93,19 @@ class AndroidComponentRegistrar : ComponentRegistrar {
|
|||||||
SyntheticResolveExtension.registerExtension(project, ParcelableResolveExtension())
|
SyntheticResolveExtension.registerExtension(project, ParcelableResolveExtension())
|
||||||
ClassBuilderInterceptorExtension.registerExtension(project, ParcelableClinitClassBuilderInterceptorExtension())
|
ClassBuilderInterceptorExtension.registerExtension(project, ParcelableClinitClassBuilderInterceptorExtension())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun parseCacheImplementationType(s: String?): CacheImplementation = when (s) {
|
||||||
|
"sparseArray" -> CacheImplementation.SPARSE_ARRAY
|
||||||
|
"none" -> CacheImplementation.NO_CACHE
|
||||||
|
else -> CacheImplementation.DEFAULT
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun registerProjectComponents(project: MockProject, configuration: CompilerConfiguration) {
|
override fun registerProjectComponents(project: MockProject, configuration: CompilerConfiguration) {
|
||||||
val applicationPackage = configuration.get(AndroidConfigurationKeys.PACKAGE)
|
val applicationPackage = configuration.get(AndroidConfigurationKeys.PACKAGE)
|
||||||
val variants = configuration.get(AndroidConfigurationKeys.VARIANT)?.mapNotNull { parseVariant(it) } ?: emptyList()
|
val variants = configuration.get(AndroidConfigurationKeys.VARIANT)?.mapNotNull { parseVariant(it) } ?: emptyList()
|
||||||
val isExperimental = configuration.get(AndroidConfigurationKeys.EXPERIMENTAL) == "true"
|
val isExperimental = configuration.get(AndroidConfigurationKeys.EXPERIMENTAL) == "true"
|
||||||
|
val globalCacheImpl = parseCacheImplementationType(configuration.get(AndroidConfigurationKeys.DEFAULT_CACHE_IMPL))
|
||||||
|
|
||||||
if (isExperimental) {
|
if (isExperimental) {
|
||||||
registerParcelExtensions(project)
|
registerParcelExtensions(project)
|
||||||
@@ -102,10 +115,10 @@ class AndroidComponentRegistrar : ComponentRegistrar {
|
|||||||
val layoutXmlFileManager = CliAndroidLayoutXmlFileManager(project, applicationPackage!!, variants)
|
val layoutXmlFileManager = CliAndroidLayoutXmlFileManager(project, applicationPackage!!, variants)
|
||||||
project.registerService(AndroidLayoutXmlFileManager::class.java, layoutXmlFileManager)
|
project.registerService(AndroidLayoutXmlFileManager::class.java, layoutXmlFileManager)
|
||||||
|
|
||||||
ExpressionCodegenExtension.registerExtension(project, CliAndroidExtensionsExpressionCodegenExtension(isExperimental))
|
ExpressionCodegenExtension.registerExtension(project, CliAndroidExtensionsExpressionCodegenExtension(isExperimental, globalCacheImpl))
|
||||||
StorageComponentContainerContributor.registerExtension(project, AndroidExtensionPropertiesComponentContainerContributor())
|
StorageComponentContainerContributor.registerExtension(project, AndroidExtensionPropertiesComponentContainerContributor())
|
||||||
Extensions.getRootArea().getExtensionPoint(DefaultErrorMessages.Extension.EP_NAME).registerExtension(DefaultErrorMessagesAndroid())
|
Extensions.getRootArea().getExtensionPoint(DefaultErrorMessages.Extension.EP_NAME).registerExtension(DefaultErrorMessagesAndroid())
|
||||||
ClassBuilderInterceptorExtension.registerExtension(project, AndroidOnDestroyClassBuilderInterceptorExtension())
|
ClassBuilderInterceptorExtension.registerExtension(project, CliAndroidOnDestroyClassBuilderInterceptorExtension(globalCacheImpl))
|
||||||
PackageFragmentProviderExtension.registerExtension(project, CliAndroidPackageFragmentProviderExtension(isExperimental))
|
PackageFragmentProviderExtension.registerExtension(project, CliAndroidPackageFragmentProviderExtension(isExperimental))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+16
-11
@@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.android.synthetic.codegen
|
package org.jetbrains.kotlin.android.synthetic.codegen
|
||||||
|
|
||||||
|
import kotlinx.android.extensions.CacheImplementation
|
||||||
import kotlinx.android.extensions.CacheImplementation.NO_CACHE
|
import kotlinx.android.extensions.CacheImplementation.NO_CACHE
|
||||||
import org.jetbrains.kotlin.android.synthetic.AndroidConst
|
import org.jetbrains.kotlin.android.synthetic.AndroidConst
|
||||||
import org.jetbrains.kotlin.android.synthetic.codegen.AndroidContainerType.LAYOUT_CONTAINER
|
import org.jetbrains.kotlin.android.synthetic.codegen.AndroidContainerType.LAYOUT_CONTAINER
|
||||||
@@ -32,6 +33,7 @@ import org.jetbrains.kotlin.codegen.state.GenerationState
|
|||||||
import org.jetbrains.kotlin.descriptors.*
|
import org.jetbrains.kotlin.descriptors.*
|
||||||
import org.jetbrains.kotlin.psi.KtClass
|
import org.jetbrains.kotlin.psi.KtClass
|
||||||
import org.jetbrains.kotlin.psi.KtClassOrObject
|
import org.jetbrains.kotlin.psi.KtClassOrObject
|
||||||
|
import org.jetbrains.kotlin.psi.KtElement
|
||||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
||||||
import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassOrAny
|
import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassOrAny
|
||||||
@@ -51,9 +53,7 @@ abstract class AbstractAndroidExtensionsExpressionCodegenExtension : ExpressionC
|
|||||||
val CLEAR_CACHE_METHOD_NAME = "_\$_clearFindViewByIdCache"
|
val CLEAR_CACHE_METHOD_NAME = "_\$_clearFindViewByIdCache"
|
||||||
val ON_DESTROY_METHOD_NAME = "onDestroyView"
|
val ON_DESTROY_METHOD_NAME = "onDestroyView"
|
||||||
|
|
||||||
fun shouldCacheResource(resource: PropertyDescriptor): Boolean {
|
fun shouldCacheResource(resource: PropertyDescriptor) = (resource as? AndroidSyntheticProperty)?.shouldBeCached == true
|
||||||
return (resource as? AndroidSyntheticProperty)?.shouldBeCached == true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private class SyntheticPartsGenerateContext(
|
private class SyntheticPartsGenerateContext(
|
||||||
@@ -63,7 +63,10 @@ abstract class AbstractAndroidExtensionsExpressionCodegenExtension : ExpressionC
|
|||||||
val classOrObject: KtClassOrObject,
|
val classOrObject: KtClassOrObject,
|
||||||
val containerOptions: ContainerOptionsProxy)
|
val containerOptions: ContainerOptionsProxy)
|
||||||
|
|
||||||
protected abstract fun isExperimental(clazz: KtClassOrObject): Boolean
|
protected abstract fun isExperimental(element: KtElement?): Boolean
|
||||||
|
protected abstract fun getGlobalCacheImpl(element: KtElement?): CacheImplementation
|
||||||
|
|
||||||
|
private fun ContainerOptionsProxy.getCacheOrDefault(element: KtElement?) = this.cache ?: getGlobalCacheImpl(element)
|
||||||
|
|
||||||
override fun applyProperty(receiver: StackValue, resolvedCall: ResolvedCall<*>, c: ExpressionCodegenExtension.Context): StackValue? {
|
override fun applyProperty(receiver: StackValue, resolvedCall: ResolvedCall<*>, c: ExpressionCodegenExtension.Context): StackValue? {
|
||||||
val resultingDescriptor = resolvedCall.resultingDescriptor
|
val resultingDescriptor = resolvedCall.resultingDescriptor
|
||||||
@@ -79,7 +82,7 @@ abstract class AbstractAndroidExtensionsExpressionCodegenExtension : ExpressionC
|
|||||||
|
|
||||||
return if (targetCallable.name.asString() == AndroidConst.CLEAR_FUNCTION_NAME) {
|
return if (targetCallable.name.asString() == AndroidConst.CLEAR_FUNCTION_NAME) {
|
||||||
val container = resolvedCall.getReceiverDeclarationDescriptor() as? ClassDescriptor ?: return null
|
val container = resolvedCall.getReceiverDeclarationDescriptor() as? ClassDescriptor ?: return null
|
||||||
generateClearFindViewByIdCacheFunctionCall(receiver, container, c)
|
generateClearFindViewByIdCacheFunctionCall(receiver, resolvedCall, container, c)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
null
|
null
|
||||||
@@ -88,12 +91,13 @@ abstract class AbstractAndroidExtensionsExpressionCodegenExtension : ExpressionC
|
|||||||
|
|
||||||
private fun generateClearFindViewByIdCacheFunctionCall(
|
private fun generateClearFindViewByIdCacheFunctionCall(
|
||||||
receiver: StackValue,
|
receiver: StackValue,
|
||||||
|
resolvedCall: ResolvedCall<*>,
|
||||||
container: ClassDescriptor,
|
container: ClassDescriptor,
|
||||||
c: ExpressionCodegenExtension.Context
|
c: ExpressionCodegenExtension.Context
|
||||||
): StackValue? {
|
): StackValue? {
|
||||||
val containerOptions = ContainerOptionsProxy.create(container)
|
val containerOptions = ContainerOptionsProxy.create(container)
|
||||||
|
|
||||||
if (!containerOptions.cache.hasCache) {
|
if (!containerOptions.getCacheOrDefault(resolvedCall.call.calleeExpression).hasCache) {
|
||||||
return StackValue.functionCall(Type.VOID_TYPE) {}
|
return StackValue.functionCall(Type.VOID_TYPE) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -119,7 +123,8 @@ abstract class AbstractAndroidExtensionsExpressionCodegenExtension : ExpressionC
|
|||||||
val container = resolvedCall.getReceiverDeclarationDescriptor() as? ClassDescriptor ?: return null
|
val container = resolvedCall.getReceiverDeclarationDescriptor() as? ClassDescriptor ?: return null
|
||||||
|
|
||||||
val containerOptions = ContainerOptionsProxy.create(container)
|
val containerOptions = ContainerOptionsProxy.create(container)
|
||||||
return ResourcePropertyStackValue(receiver, c.typeMapper, resource, container, containerOptions, androidPackage)
|
return ResourcePropertyStackValue(receiver, c.typeMapper, resource, container,
|
||||||
|
containerOptions, androidPackage, getGlobalCacheImpl(resolvedCall.call.calleeExpression))
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun ResolvedCall<*>.getReceiverDeclarationDescriptor(): ClassifierDescriptor? {
|
private fun ResolvedCall<*>.getReceiverDeclarationDescriptor(): ClassifierDescriptor? {
|
||||||
@@ -134,7 +139,7 @@ abstract class AbstractAndroidExtensionsExpressionCodegenExtension : ExpressionC
|
|||||||
if (container.kind != ClassKind.CLASS || container.isInner || DescriptorUtils.isLocal(container)) return
|
if (container.kind != ClassKind.CLASS || container.isInner || DescriptorUtils.isLocal(container)) return
|
||||||
|
|
||||||
val containerOptions = ContainerOptionsProxy.create(container)
|
val containerOptions = ContainerOptionsProxy.create(container)
|
||||||
if (containerOptions.cache == NO_CACHE) return
|
if (containerOptions.getCacheOrDefault(targetClass) == NO_CACHE) return
|
||||||
|
|
||||||
if (containerOptions.containerType == LAYOUT_CONTAINER && !isExperimental(targetClass)) {
|
if (containerOptions.containerType == LAYOUT_CONTAINER && !isExperimental(targetClass)) {
|
||||||
return
|
return
|
||||||
@@ -184,7 +189,7 @@ abstract class AbstractAndroidExtensionsExpressionCodegenExtension : ExpressionC
|
|||||||
val iv = InstructionAdapter(methodVisitor)
|
val iv = InstructionAdapter(methodVisitor)
|
||||||
|
|
||||||
val containerType = state.typeMapper.mapClass(container)
|
val containerType = state.typeMapper.mapClass(container)
|
||||||
val cacheImpl = CacheMechanism.get(containerOptions, iv, containerType)
|
val cacheImpl = CacheMechanism.get(containerOptions.getCacheOrDefault(classOrObject), iv, containerType)
|
||||||
|
|
||||||
cacheImpl.loadCache()
|
cacheImpl.loadCache()
|
||||||
val lCacheIsNull = Label()
|
val lCacheIsNull = Label()
|
||||||
@@ -199,7 +204,7 @@ abstract class AbstractAndroidExtensionsExpressionCodegenExtension : ExpressionC
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun SyntheticPartsGenerateContext.generateCacheField() {
|
private fun SyntheticPartsGenerateContext.generateCacheField() {
|
||||||
val cacheImpl = CacheMechanism.getType(containerOptions)
|
val cacheImpl = CacheMechanism.getType(containerOptions.getCacheOrDefault(classOrObject))
|
||||||
classBuilder.newField(JvmDeclarationOrigin.NO_ORIGIN, ACC_PRIVATE, PROPERTY_NAME, cacheImpl.descriptor, null, null)
|
classBuilder.newField(JvmDeclarationOrigin.NO_ORIGIN, ACC_PRIVATE, PROPERTY_NAME, cacheImpl.descriptor, null, null)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -213,7 +218,7 @@ abstract class AbstractAndroidExtensionsExpressionCodegenExtension : ExpressionC
|
|||||||
methodVisitor.visitCode()
|
methodVisitor.visitCode()
|
||||||
val iv = InstructionAdapter(methodVisitor)
|
val iv = InstructionAdapter(methodVisitor)
|
||||||
|
|
||||||
val cacheImpl = CacheMechanism.get(containerOptions, iv, containerAsmType)
|
val cacheImpl = CacheMechanism.get(containerOptions.getCacheOrDefault(classOrObject), iv, containerAsmType)
|
||||||
|
|
||||||
fun loadId() = iv.load(1, Type.INT_TYPE)
|
fun loadId() = iv.load(1, Type.INT_TYPE)
|
||||||
|
|
||||||
|
|||||||
+7
-3
@@ -17,6 +17,7 @@
|
|||||||
package org.jetbrains.kotlin.android.synthetic.codegen
|
package org.jetbrains.kotlin.android.synthetic.codegen
|
||||||
|
|
||||||
import com.intellij.psi.PsiElement
|
import com.intellij.psi.PsiElement
|
||||||
|
import kotlinx.android.extensions.CacheImplementation
|
||||||
import org.jetbrains.kotlin.android.synthetic.codegen.AbstractAndroidExtensionsExpressionCodegenExtension.Companion.ON_DESTROY_METHOD_NAME
|
import org.jetbrains.kotlin.android.synthetic.codegen.AbstractAndroidExtensionsExpressionCodegenExtension.Companion.ON_DESTROY_METHOD_NAME
|
||||||
import org.jetbrains.kotlin.android.synthetic.descriptors.ContainerOptionsProxy
|
import org.jetbrains.kotlin.android.synthetic.descriptors.ContainerOptionsProxy
|
||||||
import org.jetbrains.kotlin.codegen.ClassBuilder
|
import org.jetbrains.kotlin.codegen.ClassBuilder
|
||||||
@@ -30,9 +31,9 @@ import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin
|
|||||||
import org.jetbrains.org.objectweb.asm.*
|
import org.jetbrains.org.objectweb.asm.*
|
||||||
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
|
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
|
||||||
import org.jetbrains.kotlin.android.synthetic.codegen.AbstractAndroidExtensionsExpressionCodegenExtension.Companion.CLEAR_CACHE_METHOD_NAME
|
import org.jetbrains.kotlin.android.synthetic.codegen.AbstractAndroidExtensionsExpressionCodegenExtension.Companion.CLEAR_CACHE_METHOD_NAME
|
||||||
|
import org.jetbrains.kotlin.psi.KtElement
|
||||||
|
|
||||||
class AndroidOnDestroyClassBuilderInterceptorExtension : ClassBuilderInterceptorExtension {
|
abstract class AbstractAndroidOnDestroyClassBuilderInterceptorExtension : ClassBuilderInterceptorExtension {
|
||||||
|
|
||||||
override fun interceptClassBuilderFactory(
|
override fun interceptClassBuilderFactory(
|
||||||
interceptedFactory: ClassBuilderFactory,
|
interceptedFactory: ClassBuilderFactory,
|
||||||
bindingContext: BindingContext,
|
bindingContext: BindingContext,
|
||||||
@@ -41,6 +42,8 @@ class AndroidOnDestroyClassBuilderInterceptorExtension : ClassBuilderInterceptor
|
|||||||
return AndroidOnDestroyClassBuilderFactory(interceptedFactory, bindingContext)
|
return AndroidOnDestroyClassBuilderFactory(interceptedFactory, bindingContext)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
abstract fun getGlobalCacheImpl(element: KtElement): CacheImplementation
|
||||||
|
|
||||||
private inner class AndroidOnDestroyClassBuilderFactory(
|
private inner class AndroidOnDestroyClassBuilderFactory(
|
||||||
private val delegateFactory: ClassBuilderFactory,
|
private val delegateFactory: ClassBuilderFactory,
|
||||||
val bindingContext: BindingContext
|
val bindingContext: BindingContext
|
||||||
@@ -108,6 +111,7 @@ class AndroidOnDestroyClassBuilderInterceptorExtension : ClassBuilderInterceptor
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun generateClearCacheMethodCall() {
|
private fun generateClearCacheMethodCall() {
|
||||||
|
val currentClass = currentClass
|
||||||
if (name != ON_DESTROY_METHOD_NAME || currentClass == null) return
|
if (name != ON_DESTROY_METHOD_NAME || currentClass == null) return
|
||||||
if (Type.getArgumentTypes(desc).isNotEmpty()) return
|
if (Type.getArgumentTypes(desc).isNotEmpty()) return
|
||||||
if (Type.getReturnType(desc) != Type.VOID_TYPE) return
|
if (Type.getReturnType(desc) != Type.VOID_TYPE) return
|
||||||
@@ -116,7 +120,7 @@ class AndroidOnDestroyClassBuilderInterceptorExtension : ClassBuilderInterceptor
|
|||||||
|
|
||||||
val container = bindingContext.get(BindingContext.CLASS, currentClass) ?: return
|
val container = bindingContext.get(BindingContext.CLASS, currentClass) ?: return
|
||||||
val entityOptions = ContainerOptionsProxy.create(container)
|
val entityOptions = ContainerOptionsProxy.create(container)
|
||||||
if (!entityOptions.containerType.isFragment || !entityOptions.cache.hasCache) return
|
if (!entityOptions.containerType.isFragment || !(entityOptions.cache ?: getGlobalCacheImpl(currentClass)).hasCache) return
|
||||||
|
|
||||||
val iv = InstructionAdapter(this)
|
val iv = InstructionAdapter(this)
|
||||||
iv.load(0, containerType)
|
iv.load(0, containerType)
|
||||||
|
|||||||
+4
-5
@@ -17,7 +17,6 @@
|
|||||||
package org.jetbrains.kotlin.android.synthetic.codegen
|
package org.jetbrains.kotlin.android.synthetic.codegen
|
||||||
|
|
||||||
import kotlinx.android.extensions.CacheImplementation
|
import kotlinx.android.extensions.CacheImplementation
|
||||||
import org.jetbrains.kotlin.android.synthetic.descriptors.ContainerOptionsProxy
|
|
||||||
import org.jetbrains.org.objectweb.asm.Type
|
import org.jetbrains.org.objectweb.asm.Type
|
||||||
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
|
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
|
||||||
import org.jetbrains.kotlin.android.synthetic.codegen.AbstractAndroidExtensionsExpressionCodegenExtension.Companion.PROPERTY_NAME
|
import org.jetbrains.kotlin.android.synthetic.codegen.AbstractAndroidExtensionsExpressionCodegenExtension.Companion.PROPERTY_NAME
|
||||||
@@ -39,16 +38,16 @@ interface CacheMechanism {
|
|||||||
fun putViewToCache(getView: () -> Unit)
|
fun putViewToCache(getView: () -> Unit)
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
fun getType(containerOptions: ContainerOptionsProxy): Type {
|
fun getType(cacheImpl: CacheImplementation): Type {
|
||||||
return Type.getObjectType(when (containerOptions.cache) {
|
return Type.getObjectType(when (cacheImpl) {
|
||||||
CacheImplementation.SPARSE_ARRAY -> "android.util.SparseArray"
|
CacheImplementation.SPARSE_ARRAY -> "android.util.SparseArray"
|
||||||
CacheImplementation.HASH_MAP -> HashMap::class.java.canonicalName
|
CacheImplementation.HASH_MAP -> HashMap::class.java.canonicalName
|
||||||
CacheImplementation.NO_CACHE -> throw IllegalArgumentException("Container should support cache")
|
CacheImplementation.NO_CACHE -> throw IllegalArgumentException("Container should support cache")
|
||||||
}.replace('.', '/'))
|
}.replace('.', '/'))
|
||||||
}
|
}
|
||||||
|
|
||||||
fun get(containerOptions: ContainerOptionsProxy, iv: InstructionAdapter, containerType: Type): CacheMechanism {
|
fun get(cacheImpl: CacheImplementation, iv: InstructionAdapter, containerType: Type): CacheMechanism {
|
||||||
return when (containerOptions.cache) {
|
return when (cacheImpl) {
|
||||||
CacheImplementation.HASH_MAP -> HashMapCacheMechanism(iv, containerType)
|
CacheImplementation.HASH_MAP -> HashMapCacheMechanism(iv, containerType)
|
||||||
CacheImplementation.SPARSE_ARRAY -> SparseArrayCacheMechanism(iv, containerType)
|
CacheImplementation.SPARSE_ARRAY -> SparseArrayCacheMechanism(iv, containerType)
|
||||||
CacheImplementation.NO_CACHE -> throw IllegalArgumentException("Container should support cache")
|
CacheImplementation.NO_CACHE -> throw IllegalArgumentException("Container should support cache")
|
||||||
|
|||||||
+8
-3
@@ -16,8 +16,13 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.android.synthetic.codegen
|
package org.jetbrains.kotlin.android.synthetic.codegen
|
||||||
|
|
||||||
import org.jetbrains.kotlin.psi.KtClassOrObject
|
import kotlinx.android.extensions.CacheImplementation
|
||||||
|
import org.jetbrains.kotlin.psi.KtElement
|
||||||
|
|
||||||
class CliAndroidExtensionsExpressionCodegenExtension(val isExperimental: Boolean) : AbstractAndroidExtensionsExpressionCodegenExtension() {
|
class CliAndroidExtensionsExpressionCodegenExtension(
|
||||||
override fun isExperimental(clazz: KtClassOrObject) = isExperimental
|
val isExperimental: Boolean,
|
||||||
|
private val globalCacheImpl: CacheImplementation
|
||||||
|
) : AbstractAndroidExtensionsExpressionCodegenExtension() {
|
||||||
|
override fun isExperimental(element: KtElement?) = isExperimental
|
||||||
|
override fun getGlobalCacheImpl(element: KtElement?) = globalCacheImpl
|
||||||
}
|
}
|
||||||
+26
@@ -0,0 +1,26 @@
|
|||||||
|
/*
|
||||||
|
* 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.codegen
|
||||||
|
|
||||||
|
import kotlinx.android.extensions.CacheImplementation
|
||||||
|
import org.jetbrains.kotlin.psi.KtElement
|
||||||
|
|
||||||
|
class CliAndroidOnDestroyClassBuilderInterceptorExtension(
|
||||||
|
private val globalCacheImpl: CacheImplementation
|
||||||
|
) : AbstractAndroidOnDestroyClassBuilderInterceptorExtension() {
|
||||||
|
override fun getGlobalCacheImpl(element: KtElement) = globalCacheImpl
|
||||||
|
}
|
||||||
+4
-2
@@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.android.synthetic.codegen
|
package org.jetbrains.kotlin.android.synthetic.codegen
|
||||||
|
|
||||||
|
import kotlinx.android.extensions.CacheImplementation
|
||||||
import org.jetbrains.kotlin.android.synthetic.AndroidConst
|
import org.jetbrains.kotlin.android.synthetic.AndroidConst
|
||||||
import org.jetbrains.kotlin.android.synthetic.codegen.AbstractAndroidExtensionsExpressionCodegenExtension.Companion.shouldCacheResource
|
import org.jetbrains.kotlin.android.synthetic.codegen.AbstractAndroidExtensionsExpressionCodegenExtension.Companion.shouldCacheResource
|
||||||
import org.jetbrains.kotlin.android.synthetic.codegen.AbstractAndroidExtensionsExpressionCodegenExtension.Companion.CACHED_FIND_VIEW_BY_ID_METHOD_NAME
|
import org.jetbrains.kotlin.android.synthetic.codegen.AbstractAndroidExtensionsExpressionCodegenExtension.Companion.CACHED_FIND_VIEW_BY_ID_METHOD_NAME
|
||||||
@@ -35,7 +36,8 @@ class ResourcePropertyStackValue(
|
|||||||
val resource: PropertyDescriptor,
|
val resource: PropertyDescriptor,
|
||||||
val container: ClassDescriptor,
|
val container: ClassDescriptor,
|
||||||
private val containerOptions: ContainerOptionsProxy,
|
private val containerOptions: ContainerOptionsProxy,
|
||||||
private val androidPackage: String
|
private val androidPackage: String,
|
||||||
|
private val globalCacheImpl: CacheImplementation
|
||||||
) : StackValue(typeMapper.mapType(resource.returnType!!)) {
|
) : StackValue(typeMapper.mapType(resource.returnType!!)) {
|
||||||
private val containerType get() = containerOptions.containerType
|
private val containerType get() = containerOptions.containerType
|
||||||
|
|
||||||
@@ -51,7 +53,7 @@ class ResourcePropertyStackValue(
|
|||||||
|
|
||||||
val syntheticProperty = resource as AndroidSyntheticProperty
|
val syntheticProperty = resource as AndroidSyntheticProperty
|
||||||
|
|
||||||
if (containerOptions.cache.hasCache && shouldCacheResource(resource)) {
|
if ((containerOptions.cache ?: globalCacheImpl).hasCache && shouldCacheResource(resource)) {
|
||||||
val declarationDescriptorType = typeMapper.mapType(container)
|
val declarationDescriptorType = typeMapper.mapType(container)
|
||||||
receiver.put(declarationDescriptorType, v)
|
receiver.put(declarationDescriptorType, v)
|
||||||
|
|
||||||
|
|||||||
+6
-8
@@ -28,13 +28,11 @@ import org.jetbrains.kotlin.name.Name
|
|||||||
import org.jetbrains.kotlin.resolve.constants.EnumValue
|
import org.jetbrains.kotlin.resolve.constants.EnumValue
|
||||||
import org.jetbrains.kotlin.resolve.source.KotlinSourceElement
|
import org.jetbrains.kotlin.resolve.source.KotlinSourceElement
|
||||||
|
|
||||||
class ContainerOptionsProxy(val containerType: AndroidContainerType, val cache: CacheImplementation) {
|
class ContainerOptionsProxy(val containerType: AndroidContainerType, val cache: CacheImplementation?) {
|
||||||
companion object {
|
companion object {
|
||||||
private val CONTAINER_OPTIONS_FQNAME = FqName(ContainerOptions::class.java.canonicalName)
|
private val CONTAINER_OPTIONS_FQNAME = FqName(ContainerOptions::class.java.canonicalName)
|
||||||
private val CACHE_NAME = ContainerOptions::cache.name
|
private val CACHE_NAME = ContainerOptions::cache.name
|
||||||
|
|
||||||
private val DEFAULT_CACHE_IMPL = SPARSE_ARRAY
|
|
||||||
|
|
||||||
fun create(container: ClassDescriptor): ContainerOptionsProxy {
|
fun create(container: ClassDescriptor): ContainerOptionsProxy {
|
||||||
if (container.kind != ClassKind.CLASS) {
|
if (container.kind != ClassKind.CLASS) {
|
||||||
return ContainerOptionsProxy(AndroidContainerType.UNKNOWN, NO_CACHE)
|
return ContainerOptionsProxy(AndroidContainerType.UNKNOWN, NO_CACHE)
|
||||||
@@ -49,24 +47,24 @@ class ContainerOptionsProxy(val containerType: AndroidContainerType, val cache:
|
|||||||
val supportsCache = container.source is KotlinSourceElement && containerType.doesSupportCache
|
val supportsCache = container.source is KotlinSourceElement && containerType.doesSupportCache
|
||||||
return ContainerOptionsProxy(
|
return ContainerOptionsProxy(
|
||||||
containerType,
|
containerType,
|
||||||
if (supportsCache) DEFAULT_CACHE_IMPL else NO_CACHE)
|
if (supportsCache) null else NO_CACHE) // `null` here means "use global cache implementation setting"
|
||||||
}
|
}
|
||||||
|
|
||||||
val cache = anno.getEnumValue(CACHE_NAME, DEFAULT_CACHE_IMPL) { valueOf(it) }
|
val cache = anno.getEnumValue(CACHE_NAME) { valueOf(it) }
|
||||||
|
|
||||||
return ContainerOptionsProxy(containerType, cache)
|
return ContainerOptionsProxy(containerType, cache)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun <E : Enum<E>> AnnotationDescriptor.getEnumValue(name: String, defaultValue: E, factory: (String) -> E): E {
|
private fun <E : Enum<E>> AnnotationDescriptor.getEnumValue(name: String, factory: (String) -> E): E? {
|
||||||
val valueName = (allValueArguments[Name.identifier(name)] as? EnumValue)?.value?.name?.asString() ?: defaultValue.name
|
val valueName = (allValueArguments[Name.identifier(name)] as? EnumValue)?.value?.name?.asString() ?: return null
|
||||||
|
|
||||||
return try {
|
return try {
|
||||||
factory(valueName)
|
factory(valueName)
|
||||||
}
|
}
|
||||||
catch (e: IllegalArgumentException) {
|
catch (e: IllegalArgumentException) {
|
||||||
// Enum.valueOf() may throw this
|
// Enum.valueOf() may throw this
|
||||||
defaultValue
|
null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -25,5 +25,6 @@
|
|||||||
<orderEntry type="module" module-name="idea-jps-common" />
|
<orderEntry type="module" module-name="idea-jps-common" />
|
||||||
<orderEntry type="module" module-name="cli-common" />
|
<orderEntry type="module" module-name="cli-common" />
|
||||||
<orderEntry type="module" module-name="backend" />
|
<orderEntry type="module" module-name="backend" />
|
||||||
|
<orderEntry type="module" module-name="android-extensions-runtime" />
|
||||||
</component>
|
</component>
|
||||||
</module>
|
</module>
|
||||||
+29
-6
@@ -19,14 +19,12 @@ package org.jetbrains.kotlin.android.synthetic.idea
|
|||||||
import com.intellij.openapi.externalSystem.model.DataNode
|
import com.intellij.openapi.externalSystem.model.DataNode
|
||||||
import com.intellij.openapi.externalSystem.model.ProjectKeys
|
import com.intellij.openapi.externalSystem.model.ProjectKeys
|
||||||
import com.intellij.openapi.externalSystem.model.project.ModuleData
|
import com.intellij.openapi.externalSystem.model.project.ModuleData
|
||||||
import com.intellij.openapi.externalSystem.model.project.ProjectData
|
|
||||||
import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil
|
import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil
|
||||||
import com.intellij.openapi.util.Key
|
import com.intellij.openapi.util.Key
|
||||||
import org.gradle.api.Project
|
import org.gradle.api.Project
|
||||||
import org.gradle.tooling.model.idea.IdeaModule
|
import org.gradle.tooling.model.idea.IdeaModule
|
||||||
import org.gradle.tooling.model.idea.IdeaProject
|
|
||||||
import org.jetbrains.kotlin.android.synthetic.AndroidCommandLineProcessor
|
|
||||||
import org.jetbrains.kotlin.android.synthetic.AndroidCommandLineProcessor.Companion.ANDROID_COMPILER_PLUGIN_ID
|
import org.jetbrains.kotlin.android.synthetic.AndroidCommandLineProcessor.Companion.ANDROID_COMPILER_PLUGIN_ID
|
||||||
|
import org.jetbrains.kotlin.android.synthetic.AndroidCommandLineProcessor.Companion.DEFAULT_CACHE_IMPL_OPTION
|
||||||
import org.jetbrains.kotlin.android.synthetic.AndroidCommandLineProcessor.Companion.EXPERIMENTAL_OPTION
|
import org.jetbrains.kotlin.android.synthetic.AndroidCommandLineProcessor.Companion.EXPERIMENTAL_OPTION
|
||||||
import org.jetbrains.kotlin.android.synthetic.AndroidCommandLineProcessor.Companion.ENABLED_OPTION
|
import org.jetbrains.kotlin.android.synthetic.AndroidCommandLineProcessor.Companion.ENABLED_OPTION
|
||||||
import org.jetbrains.kotlin.cli.common.arguments.CommonCompilerArguments
|
import org.jetbrains.kotlin.cli.common.arguments.CommonCompilerArguments
|
||||||
@@ -46,14 +44,22 @@ var DataNode<ModuleData>.hasAndroidExtensionsPlugin: Boolean
|
|||||||
var DataNode<ModuleData>.isExperimental: Boolean
|
var DataNode<ModuleData>.isExperimental: Boolean
|
||||||
by NotNullableUserDataProperty(Key.create<Boolean>("ANDROID_EXTENSIONS_IS_EXPERIMENTAL"), false)
|
by NotNullableUserDataProperty(Key.create<Boolean>("ANDROID_EXTENSIONS_IS_EXPERIMENTAL"), false)
|
||||||
|
|
||||||
|
private const val DEFAULT_CACHE_IMPLEMENTATION_DEFAULT_VALUE = "hashMap"
|
||||||
|
|
||||||
|
var DataNode<ModuleData>.defaultCacheImplementation: String
|
||||||
|
by NotNullableUserDataProperty(Key.create<String>("ANDROID_EXTENSIONS_DEFAULT_CACHE_IMPL"),
|
||||||
|
DEFAULT_CACHE_IMPLEMENTATION_DEFAULT_VALUE)
|
||||||
|
|
||||||
interface AndroidExtensionsGradleModel : Serializable {
|
interface AndroidExtensionsGradleModel : Serializable {
|
||||||
val hasAndroidExtensionsPlugin: Boolean
|
val hasAndroidExtensionsPlugin: Boolean
|
||||||
val isExperimental: Boolean
|
val isExperimental: Boolean
|
||||||
|
val defaultCacheImplementation: String
|
||||||
}
|
}
|
||||||
|
|
||||||
class AndroidExtensionsGradleModelImpl(
|
class AndroidExtensionsGradleModelImpl(
|
||||||
override val hasAndroidExtensionsPlugin: Boolean,
|
override val hasAndroidExtensionsPlugin: Boolean,
|
||||||
override val isExperimental: Boolean
|
override val isExperimental: Boolean,
|
||||||
|
override val defaultCacheImplementation: String
|
||||||
) : AndroidExtensionsGradleModel
|
) : AndroidExtensionsGradleModel
|
||||||
|
|
||||||
@Suppress("unused")
|
@Suppress("unused")
|
||||||
@@ -66,6 +72,7 @@ class AndroidExtensionsProjectResolverExtension : AbstractProjectResolverExtensi
|
|||||||
|
|
||||||
ideModule.hasAndroidExtensionsPlugin = androidExtensionsModel.hasAndroidExtensionsPlugin
|
ideModule.hasAndroidExtensionsPlugin = androidExtensionsModel.hasAndroidExtensionsPlugin
|
||||||
ideModule.isExperimental = androidExtensionsModel.isExperimental
|
ideModule.isExperimental = androidExtensionsModel.isExperimental
|
||||||
|
ideModule.defaultCacheImplementation = androidExtensionsModel.defaultCacheImplementation
|
||||||
|
|
||||||
super.populateModuleExtraModels(gradleModule, ideModule)
|
super.populateModuleExtraModels(gradleModule, ideModule)
|
||||||
}
|
}
|
||||||
@@ -82,7 +89,9 @@ class AndroidExtensionsModelBuilderService : ModelBuilderService {
|
|||||||
override fun buildAll(modelName: String?, project: Project): Any {
|
override fun buildAll(modelName: String?, project: Project): Any {
|
||||||
val androidExtensionsPlugin = project.plugins.findPlugin("kotlin-android-extensions")
|
val androidExtensionsPlugin = project.plugins.findPlugin("kotlin-android-extensions")
|
||||||
|
|
||||||
val isExperimental = project.extensions.findByName("androidExtensions")?.let { ext ->
|
val androidExtensionsExtension = project.extensions.findByName("androidExtensions")
|
||||||
|
|
||||||
|
val isExperimental = androidExtensionsExtension?.let { ext ->
|
||||||
val isExperimentalMethod = ext::class.java.methods
|
val isExperimentalMethod = ext::class.java.methods
|
||||||
.firstOrNull { it.name == "isExperimental" && it.parameterCount == 0 }
|
.firstOrNull { it.name == "isExperimental" && it.parameterCount == 0 }
|
||||||
?: return@let false
|
?: return@let false
|
||||||
@@ -90,7 +99,20 @@ class AndroidExtensionsModelBuilderService : ModelBuilderService {
|
|||||||
isExperimentalMethod.invoke(ext) as? Boolean
|
isExperimentalMethod.invoke(ext) as? Boolean
|
||||||
} ?: false
|
} ?: false
|
||||||
|
|
||||||
return AndroidExtensionsGradleModelImpl(androidExtensionsPlugin != null, isExperimental)
|
val defaultCacheImplementation = androidExtensionsExtension?.let { ext ->
|
||||||
|
val defaultCacheImplementationMethod = ext::class.java.methods.firstOrNull {
|
||||||
|
it.name == "getDefaultCacheImplementation" && it.parameterCount == 0
|
||||||
|
} ?: return@let DEFAULT_CACHE_IMPLEMENTATION_DEFAULT_VALUE
|
||||||
|
|
||||||
|
val enumValue = defaultCacheImplementationMethod.invoke(ext) ?: return@let DEFAULT_CACHE_IMPLEMENTATION_DEFAULT_VALUE
|
||||||
|
|
||||||
|
val optionNameMethod = enumValue::class.java.methods.firstOrNull { it.name == "getOptionName" && it.parameterCount == 0 }
|
||||||
|
?: return@let DEFAULT_CACHE_IMPLEMENTATION_DEFAULT_VALUE
|
||||||
|
|
||||||
|
optionNameMethod.invoke(enumValue) as? String
|
||||||
|
} ?: DEFAULT_CACHE_IMPLEMENTATION_DEFAULT_VALUE
|
||||||
|
|
||||||
|
return AndroidExtensionsGradleModelImpl(androidExtensionsPlugin != null, isExperimental, defaultCacheImplementation)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -113,6 +135,7 @@ class AndroidExtensionsGradleImportHandler : GradleProjectImportHandler {
|
|||||||
if (moduleNode.hasAndroidExtensionsPlugin) {
|
if (moduleNode.hasAndroidExtensionsPlugin) {
|
||||||
newPluginOptions += makePluginOption(EXPERIMENTAL_OPTION.name, moduleNode.isExperimental.toString())
|
newPluginOptions += makePluginOption(EXPERIMENTAL_OPTION.name, moduleNode.isExperimental.toString())
|
||||||
newPluginOptions += makePluginOption(ENABLED_OPTION.name, moduleNode.hasAndroidExtensionsPlugin.toString())
|
newPluginOptions += makePluginOption(ENABLED_OPTION.name, moduleNode.hasAndroidExtensionsPlugin.toString())
|
||||||
|
newPluginOptions += makePluginOption(DEFAULT_CACHE_IMPL_OPTION.name, moduleNode.defaultCacheImplementation)
|
||||||
}
|
}
|
||||||
|
|
||||||
commonArguments.pluginOptions = newPluginOptions.toTypedArray()
|
commonArguments.pluginOptions = newPluginOptions.toTypedArray()
|
||||||
|
|||||||
+22
-6
@@ -16,20 +16,25 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.android.synthetic.idea
|
package org.jetbrains.kotlin.android.synthetic.idea
|
||||||
|
|
||||||
|
import com.intellij.openapi.application.ApplicationManager
|
||||||
import com.intellij.openapi.module.Module
|
import com.intellij.openapi.module.Module
|
||||||
|
import kotlinx.android.extensions.CacheImplementation
|
||||||
|
import org.jetbrains.android.facet.AndroidFacet
|
||||||
import org.jetbrains.kotlin.analyzer.ModuleInfo
|
import org.jetbrains.kotlin.analyzer.ModuleInfo
|
||||||
import org.jetbrains.kotlin.android.synthetic.AndroidCommandLineProcessor.Companion.ANDROID_COMPILER_PLUGIN_ID
|
import org.jetbrains.kotlin.android.synthetic.AndroidCommandLineProcessor.Companion.ANDROID_COMPILER_PLUGIN_ID
|
||||||
import org.jetbrains.kotlin.android.synthetic.AndroidCommandLineProcessor.Companion.EXPERIMENTAL_OPTION
|
import org.jetbrains.kotlin.android.synthetic.AndroidCommandLineProcessor.Companion.EXPERIMENTAL_OPTION
|
||||||
import org.jetbrains.kotlin.android.synthetic.AndroidCommandLineProcessor.Companion.ENABLED_OPTION
|
import org.jetbrains.kotlin.android.synthetic.AndroidCommandLineProcessor.Companion.ENABLED_OPTION
|
||||||
|
import org.jetbrains.kotlin.android.synthetic.AndroidCommandLineProcessor.Companion.DEFAULT_CACHE_IMPL_OPTION
|
||||||
|
import org.jetbrains.kotlin.android.synthetic.AndroidComponentRegistrar.Companion.parseCacheImplementationType
|
||||||
import org.jetbrains.kotlin.compiler.plugin.CliOption
|
import org.jetbrains.kotlin.compiler.plugin.CliOption
|
||||||
import org.jetbrains.kotlin.idea.caches.resolve.ModuleSourceInfo
|
import org.jetbrains.kotlin.idea.caches.resolve.ModuleSourceInfo
|
||||||
import org.jetbrains.kotlin.idea.facet.KotlinFacet
|
import org.jetbrains.kotlin.idea.facet.KotlinFacet
|
||||||
|
|
||||||
private val ANNOTATION_OPTION_PREFIX = "plugin:$ANDROID_COMPILER_PLUGIN_ID:"
|
private val ANNOTATION_OPTION_PREFIX = "plugin:$ANDROID_COMPILER_PLUGIN_ID:"
|
||||||
|
|
||||||
private fun Module.isOptionEnabledInFacet(option: CliOption): Boolean {
|
private fun Module.getOptionValueInFacet(option: CliOption): String? {
|
||||||
val kotlinFacet = KotlinFacet.get(this) ?: return false
|
val kotlinFacet = KotlinFacet.get(this) ?: return null
|
||||||
val commonArgs = kotlinFacet.configuration.settings.compilerArguments ?: return false
|
val commonArgs = kotlinFacet.configuration.settings.compilerArguments ?: return null
|
||||||
|
|
||||||
val prefix = ANNOTATION_OPTION_PREFIX + option.name + "="
|
val prefix = ANNOTATION_OPTION_PREFIX + option.name + "="
|
||||||
|
|
||||||
@@ -37,14 +42,25 @@ private fun Module.isOptionEnabledInFacet(option: CliOption): Boolean {
|
|||||||
?.firstOrNull { it.startsWith(prefix) }
|
?.firstOrNull { it.startsWith(prefix) }
|
||||||
?.substring(prefix.length)
|
?.substring(prefix.length)
|
||||||
|
|
||||||
return optionValue == "true"
|
return optionValue
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun isTestMode(module: Module): Boolean {
|
||||||
|
return ApplicationManager.getApplication().isUnitTestMode && AndroidFacet.getInstance(module) != null
|
||||||
}
|
}
|
||||||
|
|
||||||
internal val Module.androidExtensionsIsEnabled: Boolean
|
internal val Module.androidExtensionsIsEnabled: Boolean
|
||||||
get() = isOptionEnabledInFacet(ENABLED_OPTION)
|
get() = isTestMode(this) || getOptionValueInFacet(ENABLED_OPTION) == "true"
|
||||||
|
|
||||||
internal val ModuleInfo.androidExtensionsIsExperimental: Boolean
|
internal val ModuleInfo.androidExtensionsIsExperimental: Boolean
|
||||||
get() {
|
get() {
|
||||||
val module = (this as? ModuleSourceInfo)?.module ?: return false
|
val module = (this as? ModuleSourceInfo)?.module ?: return false
|
||||||
return module.isOptionEnabledInFacet(EXPERIMENTAL_OPTION)
|
if (isTestMode(module)) return true
|
||||||
|
return module.getOptionValueInFacet(EXPERIMENTAL_OPTION) == "true"
|
||||||
|
}
|
||||||
|
|
||||||
|
val ModuleInfo.androidExtensionsGlobalCacheImpl: CacheImplementation
|
||||||
|
get() {
|
||||||
|
val module = (this as? ModuleSourceInfo)?.module ?: return CacheImplementation.NO_CACHE
|
||||||
|
return parseCacheImplementationType(module.getOptionValueInFacet(DEFAULT_CACHE_IMPL_OPTION))
|
||||||
}
|
}
|
||||||
+7
-5
@@ -16,13 +16,15 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.android.synthetic.idea
|
package org.jetbrains.kotlin.android.synthetic.idea
|
||||||
|
|
||||||
|
import kotlinx.android.extensions.CacheImplementation
|
||||||
import org.jetbrains.kotlin.android.synthetic.codegen.AbstractAndroidExtensionsExpressionCodegenExtension
|
import org.jetbrains.kotlin.android.synthetic.codegen.AbstractAndroidExtensionsExpressionCodegenExtension
|
||||||
import org.jetbrains.kotlin.idea.caches.resolve.getModuleInfo
|
import org.jetbrains.kotlin.idea.caches.resolve.getModuleInfo
|
||||||
import org.jetbrains.kotlin.psi.KtClassOrObject
|
import org.jetbrains.kotlin.psi.KtElement
|
||||||
|
|
||||||
class IDEAndroidExtensionsExpressionCodegenExtension : AbstractAndroidExtensionsExpressionCodegenExtension() {
|
class IDEAndroidExtensionsExpressionCodegenExtension : AbstractAndroidExtensionsExpressionCodegenExtension() {
|
||||||
override fun isExperimental(clazz: KtClassOrObject): Boolean {
|
override fun isExperimental(element: KtElement?) =
|
||||||
val moduleInfo = clazz.getModuleInfo() ?: return false
|
element?.getModuleInfo()?.androidExtensionsIsExperimental ?: false
|
||||||
return moduleInfo.androidExtensionsIsExperimental
|
|
||||||
}
|
override fun getGlobalCacheImpl(element: KtElement?) =
|
||||||
|
element?.getModuleInfo()?.androidExtensionsGlobalCacheImpl ?: CacheImplementation.DEFAULT
|
||||||
}
|
}
|
||||||
+26
@@ -0,0 +1,26 @@
|
|||||||
|
/*
|
||||||
|
* 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.idea
|
||||||
|
|
||||||
|
import kotlinx.android.extensions.CacheImplementation
|
||||||
|
import org.jetbrains.kotlin.android.synthetic.codegen.AbstractAndroidOnDestroyClassBuilderInterceptorExtension
|
||||||
|
import org.jetbrains.kotlin.idea.caches.resolve.getModuleInfo
|
||||||
|
import org.jetbrains.kotlin.psi.KtElement
|
||||||
|
|
||||||
|
class IDEAndroidOnDestroyClassBuilderInterceptorExtension : AbstractAndroidOnDestroyClassBuilderInterceptorExtension() {
|
||||||
|
override fun getGlobalCacheImpl(element: KtElement) = element.getModuleInfo().androidExtensionsGlobalCacheImpl
|
||||||
|
}
|
||||||
+4
@@ -23,4 +23,8 @@ public enum class CacheImplementation {
|
|||||||
|
|
||||||
public val hasCache: Boolean
|
public val hasCache: Boolean
|
||||||
get() = this != NO_CACHE
|
get() = this != NO_CACHE
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
val DEFAULT = HASH_MAP
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -42,5 +42,6 @@
|
|||||||
<orderEntry type="module" module-name="allopen-cli" scope="TEST" />
|
<orderEntry type="module" module-name="allopen-cli" scope="TEST" />
|
||||||
<orderEntry type="module" module-name="noarg-cli" scope="TEST" />
|
<orderEntry type="module" module-name="noarg-cli" scope="TEST" />
|
||||||
<orderEntry type="module" module-name="frontend.script" />
|
<orderEntry type="module" module-name="frontend.script" />
|
||||||
|
<orderEntry type="module" module-name="android-extensions-runtime" scope="TEST" />
|
||||||
</component>
|
</component>
|
||||||
</module>
|
</module>
|
||||||
+4
-3
@@ -17,10 +17,11 @@
|
|||||||
package org.jetbrains.kotlin.android.synthetic.test
|
package org.jetbrains.kotlin.android.synthetic.test
|
||||||
|
|
||||||
import com.intellij.testFramework.registerServiceInstance
|
import com.intellij.testFramework.registerServiceInstance
|
||||||
|
import kotlinx.android.extensions.CacheImplementation
|
||||||
import org.jetbrains.kotlin.android.synthetic.AndroidConfigurationKeys
|
import org.jetbrains.kotlin.android.synthetic.AndroidConfigurationKeys
|
||||||
import org.jetbrains.kotlin.android.synthetic.AndroidExtensionPropertiesComponentContainerContributor
|
import org.jetbrains.kotlin.android.synthetic.AndroidExtensionPropertiesComponentContainerContributor
|
||||||
import org.jetbrains.kotlin.android.synthetic.codegen.AndroidOnDestroyClassBuilderInterceptorExtension
|
|
||||||
import org.jetbrains.kotlin.android.synthetic.codegen.CliAndroidExtensionsExpressionCodegenExtension
|
import org.jetbrains.kotlin.android.synthetic.codegen.CliAndroidExtensionsExpressionCodegenExtension
|
||||||
|
import org.jetbrains.kotlin.android.synthetic.codegen.CliAndroidOnDestroyClassBuilderInterceptorExtension
|
||||||
import org.jetbrains.kotlin.android.synthetic.res.AndroidLayoutXmlFileManager
|
import org.jetbrains.kotlin.android.synthetic.res.AndroidLayoutXmlFileManager
|
||||||
import org.jetbrains.kotlin.android.synthetic.res.AndroidVariant
|
import org.jetbrains.kotlin.android.synthetic.res.AndroidVariant
|
||||||
import org.jetbrains.kotlin.android.synthetic.res.CliAndroidLayoutXmlFileManager
|
import org.jetbrains.kotlin.android.synthetic.res.CliAndroidLayoutXmlFileManager
|
||||||
@@ -46,9 +47,9 @@ fun KtUsefulTestCase.createTestEnvironment(configuration: CompilerConfiguration,
|
|||||||
val variants = listOf(AndroidVariant.createMainVariant(resDirectories))
|
val variants = listOf(AndroidVariant.createMainVariant(resDirectories))
|
||||||
project.registerServiceInstance(AndroidLayoutXmlFileManager::class.java, CliAndroidLayoutXmlFileManager(project, "test", variants))
|
project.registerServiceInstance(AndroidLayoutXmlFileManager::class.java, CliAndroidLayoutXmlFileManager(project, "test", variants))
|
||||||
|
|
||||||
ExpressionCodegenExtension.registerExtension(project, CliAndroidExtensionsExpressionCodegenExtension(true))
|
ExpressionCodegenExtension.registerExtension(project, CliAndroidExtensionsExpressionCodegenExtension(true, CacheImplementation.DEFAULT))
|
||||||
StorageComponentContainerContributor.registerExtension(project, AndroidExtensionPropertiesComponentContainerContributor())
|
StorageComponentContainerContributor.registerExtension(project, AndroidExtensionPropertiesComponentContainerContributor())
|
||||||
ClassBuilderInterceptorExtension.registerExtension(project, AndroidOnDestroyClassBuilderInterceptorExtension())
|
ClassBuilderInterceptorExtension.registerExtension(project, CliAndroidOnDestroyClassBuilderInterceptorExtension(CacheImplementation.DEFAULT))
|
||||||
PackageFragmentProviderExtension.registerExtension(project, CliAndroidPackageFragmentProviderExtension(true))
|
PackageFragmentProviderExtension.registerExtension(project, CliAndroidPackageFragmentProviderExtension(true))
|
||||||
|
|
||||||
addAndroidExtensionsRuntimeLibrary(myEnvironment)
|
addAndroidExtensionsRuntimeLibrary(myEnvironment)
|
||||||
|
|||||||
Reference in New Issue
Block a user