diff --git a/compiler/testData/cli/jvm/pluginSimpleUsage.out b/compiler/testData/cli/jvm/pluginSimpleUsage.out index 738822ee38e..79bced07882 100644 --- a/compiler/testData/cli/jvm/pluginSimpleUsage.out +++ b/compiler/testData/cli/jvm/pluginSimpleUsage.out @@ -3,5 +3,6 @@ error: required plugin option not present: org.jetbrains.kotlin.android:variant Plugin "org.jetbrains.kotlin.android" usage: variant Android build variant (required, multiple) package Application package (required) + experimental true/false Enable experimental features COMPILATION_ERROR \ No newline at end of file diff --git a/idea/src/META-INF/android.xml b/idea/src/META-INF/android.xml index 7984284d734..77ae4f2fa91 100644 --- a/idea/src/META-INF/android.xml +++ b/idea/src/META-INF/android.xml @@ -66,14 +66,19 @@ + + + + - + + diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/AndroidExtensionsExtension.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/AndroidExtensionsExtension.kt new file mode 100644 index 00000000000..3f4a977430e --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/AndroidExtensionsExtension.kt @@ -0,0 +1,21 @@ +/* + * 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.gradle.internal + +open class AndroidExtensionsExtension { + open var isExperimental: Boolean = false +} \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/AndroidSubplugin.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/AndroidSubplugin.kt index b462c22c8ac..b7413efa613 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/AndroidSubplugin.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/AndroidSubplugin.kt @@ -29,15 +29,17 @@ import org.gradle.api.tasks.SourceSet import org.gradle.api.tasks.compile.AbstractCompile import org.jetbrains.kotlin.com.intellij.openapi.util.text.StringUtil.* import org.jetbrains.kotlin.gradle.plugin.* +import org.jetbrains.kotlin.gradle.plugin.android.AndroidGradleWrapper import org.jetbrains.kotlin.gradle.tasks.KotlinCompile import org.w3c.dom.Document import java.io.File import javax.xml.parsers.DocumentBuilderFactory // Use apply plugin: 'kotlin-android-extensions' to enable Android Extensions in an Android project. -// Just a marker plugin. class AndroidExtensionsSubpluginIndicator : Plugin { override fun apply(project: Project) { + project.extensions.create("androidExtensions", AndroidExtensionsExtension::class.java) + val kotlinPluginWrapper = project.plugins.findPlugin(KotlinAndroidPluginWrapper::class.java) ?: run { project.logger.error("'kotlin-android' plugin should be enabled before 'kotlin-android-extensions'") return @@ -83,13 +85,55 @@ class AndroidSubplugin : KotlinGradleSubplugin { variantData: Any?, androidProjectHandler: Any?, javaSourceSet: SourceSet? + ): List { + val androidExtension = project.extensions.getByName("android") as? BaseExtension ?: return emptyList() + val androidExtensionsExtension = project.extensions.getByType(AndroidExtensionsExtension::class.java) + + if (androidExtensionsExtension.isExperimental) { + return applyExperimental(androidExtension, project, variantData, androidProjectHandler) + } + + val sourceSets = androidExtension.sourceSets + + val pluginOptions = arrayListOf() + + val mainSourceSet = sourceSets.getByName("main") + val manifestFile = mainSourceSet.manifest.srcFile + val applicationPackage = getApplicationPackageFromManifest(manifestFile) ?: run { + project.logger.warn( + "Application package name is not present in the manifest file (${manifestFile.absolutePath})") + "" + } + pluginOptions += SubpluginOption("package", applicationPackage) + + fun addVariant(sourceSet: AndroidSourceSet) { + pluginOptions += SubpluginOption("variant", sourceSet.name + ';' + + sourceSet.res.srcDirs.joinToString(";") { it.absolutePath }) + } + + addVariant(mainSourceSet) + + val flavorSourceSets = AndroidGradleWrapper.getProductFlavorsSourceSets(androidExtension).filterNotNull() + for (sourceSet in flavorSourceSets) { + addVariant(sourceSet) + } + + return pluginOptions + } + + private fun applyExperimental( + androidExtension: BaseExtension, + project: Project, + variantData: Any?, + androidProjectHandler: Any? ): List { @Suppress("UNCHECKED_CAST") androidProjectHandler as? AbstractAndroidProjectHandler ?: return emptyList() - val androidExtension = project.extensions.getByName("android") as? BaseExtension ?: return emptyList() val pluginOptions = arrayListOf() + pluginOptions += SubpluginOption("experimental", "true") + val mainSourceSet = androidExtension.sourceSets.getByName("main") pluginOptions += SubpluginOption("package", getApplicationPackage(project, mainSourceSet)) diff --git a/plugins/android-extensions/android-extensions-compiler/src/org/jetbrains/kotlin/android/synthetic/AndroidComponentRegistrar.kt b/plugins/android-extensions/android-extensions-compiler/src/org/jetbrains/kotlin/android/synthetic/AndroidComponentRegistrar.kt index c1baae2b2ca..655f4bf1b17 100644 --- a/plugins/android-extensions/android-extensions-compiler/src/org/jetbrains/kotlin/android/synthetic/AndroidComponentRegistrar.kt +++ b/plugins/android-extensions/android-extensions-compiler/src/org/jetbrains/kotlin/android/synthetic/AndroidComponentRegistrar.kt @@ -18,8 +18,8 @@ package org.jetbrains.kotlin.android.synthetic import com.intellij.mock.MockProject import com.intellij.openapi.extensions.Extensions -import org.jetbrains.kotlin.android.synthetic.codegen.AndroidExpressionCodegenExtension import org.jetbrains.kotlin.android.synthetic.codegen.AndroidOnDestroyClassBuilderInterceptorExtension +import org.jetbrains.kotlin.android.synthetic.codegen.CliAndroidExtensionsExpressionCodegenExtension import org.jetbrains.kotlin.android.synthetic.diagnostic.AndroidExtensionPropertiesCallChecker import org.jetbrains.kotlin.android.synthetic.diagnostic.DefaultErrorMessagesAndroid import org.jetbrains.kotlin.android.synthetic.res.AndroidLayoutXmlFileManager @@ -45,6 +45,7 @@ import org.jetbrains.kotlin.resolve.jvm.platform.JvmPlatform object AndroidConfigurationKeys { val VARIANT: CompilerConfigurationKey> = CompilerConfigurationKey.create>("Android build variant") val PACKAGE: CompilerConfigurationKey = CompilerConfigurationKey.create("application package fq name") + val EXPERIMENTAL: CompilerConfigurationKey = CompilerConfigurationKey.create("enable experimental features") } class AndroidCommandLineProcessor : CommandLineProcessor { @@ -53,36 +54,41 @@ class AndroidCommandLineProcessor : CommandLineProcessor { val VARIANT_OPTION: CliOption = CliOption("variant", "", "Android build variant", allowMultipleOccurrences = true) val PACKAGE_OPTION: CliOption = CliOption("package", "", "Application package") + val EXPERIMENTAL_OPTION: CliOption = CliOption("experimental", "true/false", "Enable experimental features", required = false) + + /* 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) } override val pluginId: String = ANDROID_COMPILER_PLUGIN_ID - override val pluginOptions: Collection = listOf(VARIANT_OPTION, PACKAGE_OPTION) + override val pluginOptions: Collection = listOf(VARIANT_OPTION, PACKAGE_OPTION, EXPERIMENTAL_OPTION) override fun processOption(option: CliOption, value: String, configuration: CompilerConfiguration) { when (option) { VARIANT_OPTION -> configuration.appendList(AndroidConfigurationKeys.VARIANT, value) PACKAGE_OPTION -> configuration.put(AndroidConfigurationKeys.PACKAGE, value) + EXPERIMENTAL_OPTION -> configuration.put(AndroidConfigurationKeys.EXPERIMENTAL, value) else -> throw CliOptionProcessingException("Unknown option: ${option.name}") } } } class AndroidComponentRegistrar : ComponentRegistrar { - override fun registerProjectComponents(project: MockProject, configuration: CompilerConfiguration) { val applicationPackage = configuration.get(AndroidConfigurationKeys.PACKAGE) val variants = configuration.get(AndroidConfigurationKeys.VARIANT)?.mapNotNull { parseVariant(it) } ?: emptyList() + val isExperimental = configuration.get(AndroidConfigurationKeys.EXPERIMENTAL) == "true" if (variants.isNotEmpty() && !applicationPackage.isNullOrBlank()) { val layoutXmlFileManager = CliAndroidLayoutXmlFileManager(project, applicationPackage!!, variants) project.registerService(AndroidLayoutXmlFileManager::class.java, layoutXmlFileManager) - ExpressionCodegenExtension.registerExtension(project, AndroidExpressionCodegenExtension()) + ExpressionCodegenExtension.registerExtension(project, CliAndroidExtensionsExpressionCodegenExtension(isExperimental)) StorageComponentContainerContributor.registerExtension(project, AndroidExtensionPropertiesComponentContainerContributor()) Extensions.getRootArea().getExtensionPoint(DefaultErrorMessages.Extension.EP_NAME).registerExtension(DefaultErrorMessagesAndroid()) ClassBuilderInterceptorExtension.registerExtension(project, AndroidOnDestroyClassBuilderInterceptorExtension()) - PackageFragmentProviderExtension.registerExtension(project, CliAndroidPackageFragmentProviderExtension()) + PackageFragmentProviderExtension.registerExtension(project, CliAndroidPackageFragmentProviderExtension(isExperimental)) } } 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/AbstractAndroidExtensionsExpressionCodegenExtension.kt similarity index 95% rename from plugins/android-extensions/android-extensions-compiler/src/org/jetbrains/kotlin/android/synthetic/codegen/AndroidExpressionCodegenExtension.kt rename to plugins/android-extensions/android-extensions-compiler/src/org/jetbrains/kotlin/android/synthetic/codegen/AbstractAndroidExtensionsExpressionCodegenExtension.kt index 0384b7dbe55..446ab4daeb4 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/AbstractAndroidExtensionsExpressionCodegenExtension.kt @@ -18,6 +18,7 @@ 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.codegen.AndroidContainerType.LAYOUT_CONTAINER import org.jetbrains.kotlin.android.synthetic.descriptors.ContainerOptionsProxy import org.jetbrains.kotlin.android.synthetic.descriptors.AndroidSyntheticPackageFragmentDescriptor import org.jetbrains.kotlin.android.synthetic.res.AndroidSyntheticFunction @@ -29,6 +30,7 @@ import org.jetbrains.kotlin.codegen.StackValue import org.jetbrains.kotlin.codegen.extensions.ExpressionCodegenExtension import org.jetbrains.kotlin.codegen.state.GenerationState import org.jetbrains.kotlin.descriptors.* +import org.jetbrains.kotlin.psi.KtClass import org.jetbrains.kotlin.psi.KtClassOrObject import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall @@ -42,7 +44,7 @@ import org.jetbrains.org.objectweb.asm.Opcodes.ACC_SYNTHETIC import org.jetbrains.org.objectweb.asm.Type import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter -class AndroidExpressionCodegenExtension : ExpressionCodegenExtension { +abstract class AbstractAndroidExtensionsExpressionCodegenExtension : ExpressionCodegenExtension { companion object { val PROPERTY_NAME = "_\$_findViewCache" val CACHED_FIND_VIEW_BY_ID_METHOD_NAME = "_\$_findCachedViewById" @@ -61,6 +63,8 @@ class AndroidExpressionCodegenExtension : ExpressionCodegenExtension { val classOrObject: KtClassOrObject, val containerOptions: ContainerOptionsProxy) + protected abstract fun isExperimental(clazz: KtClassOrObject): Boolean + override fun applyProperty(receiver: StackValue, resolvedCall: ResolvedCall<*>, c: ExpressionCodegenExtension.Context): StackValue? { val resultingDescriptor = resolvedCall.resultingDescriptor return if (resultingDescriptor is PropertyDescriptor) { @@ -124,7 +128,7 @@ class AndroidExpressionCodegenExtension : ExpressionCodegenExtension { override fun generateClassSyntheticParts(codegen: ImplementationBodyCodegen) { val classBuilder = codegen.v - val targetClass = codegen.myClass as? KtClassOrObject ?: return + val targetClass = codegen.myClass as? KtClass ?: return val container = codegen.descriptor if (container.kind != ClassKind.CLASS || container.isInner || DescriptorUtils.isLocal(container)) return @@ -132,6 +136,10 @@ class AndroidExpressionCodegenExtension : ExpressionCodegenExtension { val containerOptions = ContainerOptionsProxy.create(container) if (containerOptions.cache == NO_CACHE) return + if (containerOptions.containerType == LAYOUT_CONTAINER && !isExperimental(targetClass)) { + return + } + val context = SyntheticPartsGenerateContext(classBuilder, codegen.state, container, targetClass, containerOptions) context.generateCachedFindViewByIdFunction() context.generateClearCacheFunction() @@ -239,8 +247,8 @@ class AndroidExpressionCodegenExtension : ExpressionCodegenExtension { loadId() iv.invokevirtual(containerType.internalClassName, "findViewById", "(I)Landroid/view/View;", false) } - AndroidContainerType.FRAGMENT, AndroidContainerType.SUPPORT_FRAGMENT, AndroidContainerType.LAYOUT_CONTAINER -> { - if (containerType == AndroidContainerType.LAYOUT_CONTAINER) { + AndroidContainerType.FRAGMENT, AndroidContainerType.SUPPORT_FRAGMENT, LAYOUT_CONTAINER -> { + if (containerType == LAYOUT_CONTAINER) { iv.invokeinterface(containerType.internalClassName, "getContainerView", "()Landroid/view/View;") } else { iv.invokevirtual(containerType.internalClassName, "getView", "()Landroid/view/View;", false) 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 b7c42daaa7a..38ad611ba52 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,7 @@ package org.jetbrains.kotlin.android.synthetic.codegen import com.intellij.psi.PsiElement +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.codegen.ClassBuilder import org.jetbrains.kotlin.codegen.ClassBuilderFactory @@ -28,6 +29,7 @@ import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin import org.jetbrains.org.objectweb.asm.* import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter +import org.jetbrains.kotlin.android.synthetic.codegen.AbstractAndroidExtensionsExpressionCodegenExtension.Companion.CLEAR_CACHE_METHOD_NAME class AndroidOnDestroyClassBuilderInterceptorExtension : ClassBuilderInterceptorExtension { @@ -106,7 +108,7 @@ class AndroidOnDestroyClassBuilderInterceptorExtension : ClassBuilderInterceptor } private fun generateClearCacheMethodCall() { - if (name != AndroidExpressionCodegenExtension.ON_DESTROY_METHOD_NAME || currentClass == null) return + if (name != ON_DESTROY_METHOD_NAME || currentClass == null) return if (Type.getArgumentTypes(desc).isNotEmpty()) return if (Type.getReturnType(desc) != Type.VOID_TYPE) return @@ -118,7 +120,7 @@ class AndroidOnDestroyClassBuilderInterceptorExtension : ClassBuilderInterceptor val iv = InstructionAdapter(this) iv.load(0, containerType) - iv.invokevirtual(currentClassName, AndroidExpressionCodegenExtension.CLEAR_CACHE_METHOD_NAME, "()V", false) + iv.invokevirtual(currentClassName, CLEAR_CACHE_METHOD_NAME, "()V", false) } } } diff --git a/plugins/android-extensions/android-extensions-compiler/src/org/jetbrains/kotlin/android/synthetic/codegen/CacheMechanisms.kt b/plugins/android-extensions/android-extensions-compiler/src/org/jetbrains/kotlin/android/synthetic/codegen/CacheMechanisms.kt index 90f69117f6a..75a8fff6452 100644 --- a/plugins/android-extensions/android-extensions-compiler/src/org/jetbrains/kotlin/android/synthetic/codegen/CacheMechanisms.kt +++ b/plugins/android-extensions/android-extensions-compiler/src/org/jetbrains/kotlin/android/synthetic/codegen/CacheMechanisms.kt @@ -20,6 +20,7 @@ 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.commons.InstructionAdapter +import org.jetbrains.kotlin.android.synthetic.codegen.AbstractAndroidExtensionsExpressionCodegenExtension.Companion.PROPERTY_NAME interface CacheMechanism { /** Push the cache object onto the stack. */ @@ -62,7 +63,7 @@ internal class HashMapCacheMechanism( ) : CacheMechanism { override fun loadCache() { iv.load(0, containerType) - iv.getfield(containerType.internalName, AndroidExpressionCodegenExtension.PROPERTY_NAME, "Ljava/util/HashMap;") + iv.getfield(containerType.internalName, PROPERTY_NAME, "Ljava/util/HashMap;") } override fun initCache() { @@ -70,7 +71,7 @@ internal class HashMapCacheMechanism( iv.anew(Type.getType("Ljava/util/HashMap;")) iv.dup() iv.invokespecial("java/util/HashMap", "", "()V", false) - iv.putfield(containerType.internalName, AndroidExpressionCodegenExtension.PROPERTY_NAME, "Ljava/util/HashMap;") + iv.putfield(containerType.internalName, PROPERTY_NAME, "Ljava/util/HashMap;") } override fun clearCache() { @@ -96,7 +97,7 @@ internal class SparseArrayCacheMechanism( ) : CacheMechanism { override fun loadCache() { iv.load(0, containerType) - iv.getfield(containerType.internalName, AndroidExpressionCodegenExtension.PROPERTY_NAME, "Landroid/util/SparseArray;") + iv.getfield(containerType.internalName, PROPERTY_NAME, "Landroid/util/SparseArray;") } override fun initCache() { @@ -104,7 +105,7 @@ internal class SparseArrayCacheMechanism( iv.anew(Type.getType("Landroid/util/SparseArray;")) iv.dup() iv.invokespecial("android/util/SparseArray", "", "()V", false) - iv.putfield(containerType.internalName, AndroidExpressionCodegenExtension.PROPERTY_NAME, "Landroid/util/SparseArray;") + iv.putfield(containerType.internalName, PROPERTY_NAME, "Landroid/util/SparseArray;") } override fun clearCache() { diff --git a/plugins/android-extensions/android-extensions-compiler/src/org/jetbrains/kotlin/android/synthetic/codegen/CliAndroidExtensionsExpressionCodegenExtension.kt b/plugins/android-extensions/android-extensions-compiler/src/org/jetbrains/kotlin/android/synthetic/codegen/CliAndroidExtensionsExpressionCodegenExtension.kt new file mode 100644 index 00000000000..14bdfcd1103 --- /dev/null +++ b/plugins/android-extensions/android-extensions-compiler/src/org/jetbrains/kotlin/android/synthetic/codegen/CliAndroidExtensionsExpressionCodegenExtension.kt @@ -0,0 +1,23 @@ +/* + * 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 org.jetbrains.kotlin.psi.KtClassOrObject + +class CliAndroidExtensionsExpressionCodegenExtension(val isExperimental: Boolean) : AbstractAndroidExtensionsExpressionCodegenExtension() { + override fun isExperimental(clazz: KtClassOrObject) = isExperimental +} \ No newline at end of file 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 83550f7dcb5..a17cadd86ed 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,7 +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.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.descriptors.ContainerOptionsProxy import org.jetbrains.kotlin.android.synthetic.res.AndroidSyntheticProperty import org.jetbrains.kotlin.codegen.StackValue @@ -58,7 +59,7 @@ class ResourcePropertyStackValue( val packageName = resourceId.packageName ?: androidPackage v.getstatic(packageName.replace(".", "/") + "/R\$id", resourceId.name, "I") - v.invokevirtual(declarationDescriptorType.internalName, AndroidExpressionCodegenExtension.CACHED_FIND_VIEW_BY_ID_METHOD_NAME, "(I)Landroid/view/View;", false) + v.invokevirtual(declarationDescriptorType.internalName, CACHED_FIND_VIEW_BY_ID_METHOD_NAME, "(I)Landroid/view/View;", false) } else { when (containerType) { diff --git a/plugins/android-extensions/android-extensions-compiler/src/org/jetbrains/kotlin/android/synthetic/descriptors/AndroidSyntheticPackageFragmentDescriptor.kt b/plugins/android-extensions/android-extensions-compiler/src/org/jetbrains/kotlin/android/synthetic/descriptors/AndroidSyntheticPackageFragmentDescriptor.kt index 76681a7e406..3f6f0434b73 100644 --- a/plugins/android-extensions/android-extensions-compiler/src/org/jetbrains/kotlin/android/synthetic/descriptors/AndroidSyntheticPackageFragmentDescriptor.kt +++ b/plugins/android-extensions/android-extensions-compiler/src/org/jetbrains/kotlin/android/synthetic/descriptors/AndroidSyntheticPackageFragmentDescriptor.kt @@ -42,7 +42,8 @@ class AndroidSyntheticPackageFragmentDescriptor( fqName: FqName, val packageData: AndroidSyntheticPackageData, private val lazyContext: LazySyntheticElementResolveContext, - private val storageManager: StorageManager + private val storageManager: StorageManager, + private val isExperimental: Boolean ) : PackageFragmentDescriptorImpl(module, fqName) { private val scope = AndroidExtensionPropertiesScope() override fun getMemberScope(): MemberScope = scope @@ -52,7 +53,7 @@ class AndroidSyntheticPackageFragmentDescriptor( val packageFragmentDescriptor = this@AndroidSyntheticPackageFragmentDescriptor val context = lazyContext() - val widgetReceivers = context.getWidgetReceivers(packageData.forView) + val widgetReceivers = context.getWidgetReceivers(packageData.forView, isExperimental) val fragmentTypes = context.fragmentTypes val properties = ArrayList(0) diff --git a/plugins/android-extensions/android-extensions-compiler/src/org/jetbrains/kotlin/android/synthetic/descriptors/LazySyntheticElementResolveContext.kt b/plugins/android-extensions/android-extensions-compiler/src/org/jetbrains/kotlin/android/synthetic/descriptors/LazySyntheticElementResolveContext.kt index 2d36883dc67..d7825b6b9cf 100644 --- a/plugins/android-extensions/android-extensions-compiler/src/org/jetbrains/kotlin/android/synthetic/descriptors/LazySyntheticElementResolveContext.kt +++ b/plugins/android-extensions/android-extensions-compiler/src/org/jetbrains/kotlin/android/synthetic/descriptors/LazySyntheticElementResolveContext.kt @@ -77,6 +77,11 @@ internal class SyntheticElementResolveContext( receivers += WidgetReceiver(dialog, mayHaveCache = false) fragment?.let { receivers += WidgetReceiver(it, mayHaveCache = true) } supportFragment?.let { receivers += WidgetReceiver(it, mayHaveCache = true) } + receivers + } + + private val experimentalWidgetReceivers by lazy { + val receivers = widgetReceivers.toMutableList() layoutContainer?.let { receivers += WidgetReceiver(it, mayHaveCache = true) } receivers } @@ -97,9 +102,9 @@ internal class SyntheticElementResolveContext( } } - fun getWidgetReceivers(forView: Boolean): List { + fun getWidgetReceivers(forView: Boolean, isExperimental: Boolean): List { if (forView) return listOf(WidgetReceiver(view, mayHaveCache = true)) - return widgetReceivers + return if (isExperimental) experimentalWidgetReceivers else widgetReceivers } } diff --git a/plugins/android-extensions/android-extensions-compiler/src/org/jetbrains/kotlin/android/synthetic/res/AndroidPackageFragmentProviderExtension.kt b/plugins/android-extensions/android-extensions-compiler/src/org/jetbrains/kotlin/android/synthetic/res/AndroidPackageFragmentProviderExtension.kt index 28ec7de346e..b117f11fa5c 100644 --- a/plugins/android-extensions/android-extensions-compiler/src/org/jetbrains/kotlin/android/synthetic/res/AndroidPackageFragmentProviderExtension.kt +++ b/plugins/android-extensions/android-extensions-compiler/src/org/jetbrains/kotlin/android/synthetic/res/AndroidPackageFragmentProviderExtension.kt @@ -31,6 +31,8 @@ import org.jetbrains.kotlin.storage.StorageManager abstract class AndroidPackageFragmentProviderExtension : PackageFragmentProviderExtension { protected abstract fun getLayoutXmlFileManager(project: Project, moduleInfo: ModuleInfo?): AndroidLayoutXmlFileManager? + protected abstract fun isExperimental(moduleInfo: ModuleInfo?): Boolean + override fun getPackageFragmentProvider( project: Project, module: ModuleDescriptor, @@ -38,6 +40,8 @@ abstract class AndroidPackageFragmentProviderExtension : PackageFragmentProvider trace: BindingTrace, moduleInfo: ModuleInfo? ): PackageFragmentProvider? { + val isExperimental = isExperimental(moduleInfo) + val layoutXmlFileManager = getLayoutXmlFileManager(project, moduleInfo) ?: return null val moduleData = layoutXmlFileManager.getModuleData() @@ -54,7 +58,7 @@ abstract class AndroidPackageFragmentProviderExtension : PackageFragmentProvider val resources = layoutXmlFileManager.extractResources(AndroidLayoutGroupData(layoutName, layouts), module) val packageData = AndroidSyntheticPackageData(moduleData, forView, isDeprecated, resources) val packageDescriptor = AndroidSyntheticPackageFragmentDescriptor( - module, FqName(fqName), packageData, lazyContext, storageManager) + module, FqName(fqName), packageData, lazyContext, storageManager, isExperimental) packagesToLookupInCompletion += packageDescriptor allPackageDescriptors += packageDescriptor } @@ -79,7 +83,10 @@ abstract class AndroidPackageFragmentProviderExtension : PackageFragmentProvider // Package with clearFindViewByIdCache() AndroidConst.SYNTHETIC_SUBPACKAGES.last().let { s -> val packageDescriptor = PredefinedPackageFragmentDescriptor(s, module, storageManager, packagesToLookupInCompletion) { descriptor -> - (lazyContext().getWidgetReceivers(forView = false) + lazyContext().getWidgetReceivers(forView = true)) + val widgetReceivers = lazyContext().getWidgetReceivers(forView = false, isExperimental = isExperimental) + + lazyContext().getWidgetReceivers(forView = true, isExperimental = isExperimental) + + widgetReceivers .filter { it.mayHaveCache } .map { genClearCacheFunction(descriptor, it.type) } } diff --git a/plugins/android-extensions/android-extensions-compiler/src/org/jetbrains/kotlin/android/synthetic/res/CliAndroidPackageFragmentProviderExtension.kt b/plugins/android-extensions/android-extensions-compiler/src/org/jetbrains/kotlin/android/synthetic/res/CliAndroidPackageFragmentProviderExtension.kt index 2178d2b75f2..a785731ae28 100644 --- a/plugins/android-extensions/android-extensions-compiler/src/org/jetbrains/kotlin/android/synthetic/res/CliAndroidPackageFragmentProviderExtension.kt +++ b/plugins/android-extensions/android-extensions-compiler/src/org/jetbrains/kotlin/android/synthetic/res/CliAndroidPackageFragmentProviderExtension.kt @@ -17,10 +17,13 @@ package org.jetbrains.kotlin.android.synthetic.res import com.intellij.openapi.components.ServiceManager +import com.intellij.openapi.module.Module import com.intellij.openapi.project.Project import org.jetbrains.kotlin.analyzer.ModuleInfo -class CliAndroidPackageFragmentProviderExtension : AndroidPackageFragmentProviderExtension() { +class CliAndroidPackageFragmentProviderExtension(private val isExperimental: Boolean) : AndroidPackageFragmentProviderExtension() { + override fun isExperimental(moduleInfo: ModuleInfo?): Boolean = isExperimental + override fun getLayoutXmlFileManager(project: Project, moduleInfo: ModuleInfo?): AndroidLayoutXmlFileManager? { return ServiceManager.getService(project, AndroidLayoutXmlFileManager::class.java) } diff --git a/plugins/android-extensions/android-extensions-idea/android-extensions-idea.iml b/plugins/android-extensions/android-extensions-idea/android-extensions-idea.iml index 443993ce359..824738f3711 100644 --- a/plugins/android-extensions/android-extensions-idea/android-extensions-idea.iml +++ b/plugins/android-extensions/android-extensions-idea/android-extensions-idea.iml @@ -22,5 +22,8 @@ + + + \ No newline at end of file diff --git a/plugins/android-extensions/android-extensions-idea/src/META-INF/services/org.jetbrains.plugins.gradle.tooling.ModelBuilderService b/plugins/android-extensions/android-extensions-idea/src/META-INF/services/org.jetbrains.plugins.gradle.tooling.ModelBuilderService new file mode 100644 index 00000000000..e7801906f5b --- /dev/null +++ b/plugins/android-extensions/android-extensions-idea/src/META-INF/services/org.jetbrains.plugins.gradle.tooling.ModelBuilderService @@ -0,0 +1 @@ +org.jetbrains.kotlin.android.synthetic.idea.AndroidExtensionsModelBuilderService \ No newline at end of file diff --git a/plugins/android-extensions/android-extensions-idea/src/org/jetbrains/kotlin/android/synthetic/idea/AndroidExtensionsProjectResolverExtension.kt b/plugins/android-extensions/android-extensions-idea/src/org/jetbrains/kotlin/android/synthetic/idea/AndroidExtensionsProjectResolverExtension.kt new file mode 100644 index 00000000000..4d8b7b2f923 --- /dev/null +++ b/plugins/android-extensions/android-extensions-idea/src/org/jetbrains/kotlin/android/synthetic/idea/AndroidExtensionsProjectResolverExtension.kt @@ -0,0 +1,121 @@ +/* + * 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 com.intellij.openapi.externalSystem.model.DataNode +import com.intellij.openapi.externalSystem.model.ProjectKeys +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.util.Key +import org.gradle.api.Project +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.EXPERIMENTAL_OPTION +import org.jetbrains.kotlin.android.synthetic.AndroidCommandLineProcessor.Companion.ENABLED_OPTION +import org.jetbrains.kotlin.cli.common.arguments.CommonCompilerArguments +import org.jetbrains.kotlin.idea.configuration.GradleProjectImportHandler +import org.jetbrains.kotlin.idea.facet.KotlinFacet +import org.jetbrains.kotlin.psi.NotNullableUserDataProperty +import org.jetbrains.plugins.gradle.model.data.GradleSourceSetData +import org.jetbrains.plugins.gradle.service.project.AbstractProjectResolverExtension +import org.jetbrains.plugins.gradle.tooling.ErrorMessageBuilder +import org.jetbrains.plugins.gradle.tooling.ModelBuilderService +import java.io.Serializable +import java.lang.Exception + +var DataNode.hasAndroidExtensionsPlugin: Boolean + by NotNullableUserDataProperty(Key.create("HAS_ANDROID_EXTENSIONS_PLUGIN"), false) + +var DataNode.isExperimental: Boolean + by NotNullableUserDataProperty(Key.create("ANDROID_EXTENSIONS_IS_EXPERIMENTAL"), false) + +interface AndroidExtensionsGradleModel : Serializable { + val hasAndroidExtensionsPlugin: Boolean + val isExperimental: Boolean +} + +class AndroidExtensionsGradleModelImpl( + override val hasAndroidExtensionsPlugin: Boolean, + override val isExperimental: Boolean +) : AndroidExtensionsGradleModel + +@Suppress("unused") +class AndroidExtensionsProjectResolverExtension : AbstractProjectResolverExtension() { + override fun getExtraProjectModelClasses() = setOf(AndroidExtensionsGradleModel::class.java) + override fun getToolingExtensionsClasses() = setOf(AndroidExtensionsModelBuilderService::class.java) + + override fun populateModuleExtraModels(gradleModule: IdeaModule, ideModule: DataNode) { + val androidExtensionsModel = resolverCtx.getExtraProject(gradleModule, AndroidExtensionsGradleModel::class.java) ?: return + + ideModule.hasAndroidExtensionsPlugin = androidExtensionsModel.hasAndroidExtensionsPlugin + ideModule.isExperimental = androidExtensionsModel.isExperimental + + super.populateModuleExtraModels(gradleModule, ideModule) + } +} + +class AndroidExtensionsModelBuilderService : ModelBuilderService { + override fun getErrorMessageBuilder(project: Project, e: Exception): ErrorMessageBuilder { + return ErrorMessageBuilder.create(project, e, "Gradle import errors") + .withDescription("Unable to build Android Extensions plugin configuration") + } + + override fun canBuild(modelName: String?): Boolean = modelName == AndroidExtensionsGradleModel::class.java.name + + override fun buildAll(modelName: String?, project: Project): Any { + val androidExtensionsPlugin = project.plugins.findPlugin("kotlin-android-extensions") + + val isExperimental = project.extensions.findByName("androidExtensions")?.let { ext -> + val isExperimentalMethod = ext::class.java.methods + .firstOrNull { it.name == "isExperimental" && it.parameterCount == 0 } + ?: return@let false + + isExperimentalMethod.invoke(ext) as? Boolean + } ?: false + + return AndroidExtensionsGradleModelImpl(androidExtensionsPlugin != null, isExperimental) + } +} + +@Suppress("unused") +class AndroidExtensionsGradleImportHandler : GradleProjectImportHandler { + override fun importBySourceSet(facet: KotlinFacet, sourceSetNode: DataNode) { + val module = ExternalSystemApiUtil.findParent(sourceSetNode, ProjectKeys.MODULE) ?: return + importByModule(facet, module) + } + + override fun importByModule(facet: KotlinFacet, moduleNode: DataNode) { + val facetSettings = facet.configuration.settings + val commonArguments = facetSettings.compilerArguments ?: CommonCompilerArguments.DummyImpl() + + fun makePluginOption(key: String, value: String) = "plugin:$ANDROID_COMPILER_PLUGIN_ID:$key=$value" + + val newPluginOptions = (commonArguments.pluginOptions ?: emptyArray()) + .filterTo(mutableListOf()) { !it.startsWith("plugin:$ANDROID_COMPILER_PLUGIN_ID:") } // Filter out old options + + if (moduleNode.hasAndroidExtensionsPlugin) { + newPluginOptions += makePluginOption(EXPERIMENTAL_OPTION.name, moduleNode.isExperimental.toString()) + newPluginOptions += makePluginOption(ENABLED_OPTION.name, moduleNode.hasAndroidExtensionsPlugin.toString()) + } + + commonArguments.pluginOptions = newPluginOptions.toTypedArray() + facetSettings.compilerArguments = commonArguments + } +} \ No newline at end of file diff --git a/plugins/android-extensions/android-extensions-idea/src/org/jetbrains/kotlin/android/synthetic/idea/ExperimentalUtils.kt b/plugins/android-extensions/android-extensions-idea/src/org/jetbrains/kotlin/android/synthetic/idea/ExperimentalUtils.kt new file mode 100644 index 00000000000..9aed71e2a85 --- /dev/null +++ b/plugins/android-extensions/android-extensions-idea/src/org/jetbrains/kotlin/android/synthetic/idea/ExperimentalUtils.kt @@ -0,0 +1,38 @@ +/* + * 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 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.EXPERIMENTAL_OPTION +import org.jetbrains.kotlin.idea.caches.resolve.ModuleSourceInfo +import org.jetbrains.kotlin.idea.facet.KotlinFacet + +private val ANNOTATION_OPTION_PREFIX = "plugin:$ANDROID_COMPILER_PLUGIN_ID:${EXPERIMENTAL_OPTION.name}=" + +internal val ModuleInfo.androidExtensionsIsExperimental: Boolean + get() { + val module = (this as? ModuleSourceInfo)?.module ?: return false + val kotlinFacet = KotlinFacet.get(module) ?: return false + val commonArgs = kotlinFacet.configuration.settings.compilerArguments ?: return false + + val isExperimentalString = commonArgs.pluginOptions + ?.firstOrNull { it.startsWith(ANNOTATION_OPTION_PREFIX) } + ?.substring(ANNOTATION_OPTION_PREFIX.length) + + return isExperimentalString == "true" + } \ No newline at end of file diff --git a/plugins/android-extensions/android-extensions-idea/src/org/jetbrains/kotlin/android/synthetic/idea/IDEAndroidExtensionsExpressionCodegenExtension.kt b/plugins/android-extensions/android-extensions-idea/src/org/jetbrains/kotlin/android/synthetic/idea/IDEAndroidExtensionsExpressionCodegenExtension.kt new file mode 100644 index 00000000000..0cd53e38a58 --- /dev/null +++ b/plugins/android-extensions/android-extensions-idea/src/org/jetbrains/kotlin/android/synthetic/idea/IDEAndroidExtensionsExpressionCodegenExtension.kt @@ -0,0 +1,28 @@ +/* + * 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 org.jetbrains.kotlin.android.synthetic.codegen.AbstractAndroidExtensionsExpressionCodegenExtension +import org.jetbrains.kotlin.idea.caches.resolve.getModuleInfo +import org.jetbrains.kotlin.psi.KtClassOrObject + +class IDEAndroidExtensionsExpressionCodegenExtension : AbstractAndroidExtensionsExpressionCodegenExtension() { + override fun isExperimental(clazz: KtClassOrObject): Boolean { + val moduleInfo = clazz.getModuleInfo() ?: return false + return moduleInfo.androidExtensionsIsExperimental + } +} \ No newline at end of file diff --git a/plugins/android-extensions/android-extensions-idea/src/org/jetbrains/kotlin/android/synthetic/idea/res/IDEAndroidPackageFragmentProviderExtension.kt b/plugins/android-extensions/android-extensions-idea/src/org/jetbrains/kotlin/android/synthetic/idea/res/IDEAndroidPackageFragmentProviderExtension.kt index 1fe42b0e04c..56a5e54f50e 100644 --- a/plugins/android-extensions/android-extensions-idea/src/org/jetbrains/kotlin/android/synthetic/idea/res/IDEAndroidPackageFragmentProviderExtension.kt +++ b/plugins/android-extensions/android-extensions-idea/src/org/jetbrains/kotlin/android/synthetic/idea/res/IDEAndroidPackageFragmentProviderExtension.kt @@ -25,14 +25,23 @@ import com.intellij.openapi.project.Project import com.intellij.psi.PsiManager import org.jetbrains.android.facet.AndroidFacet 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.EXPERIMENTAL_OPTION +import org.jetbrains.kotlin.android.synthetic.idea.androidExtensionsIsExperimental +import org.jetbrains.kotlin.android.synthetic.idea.isExperimental import org.jetbrains.kotlin.android.synthetic.res.AndroidLayoutXmlFileManager import org.jetbrains.kotlin.android.synthetic.res.AndroidPackageFragmentProviderExtension import org.jetbrains.kotlin.idea.caches.resolve.ModuleSourceInfo +import org.jetbrains.kotlin.idea.facet.KotlinFacet import org.jetbrains.plugins.groovy.lang.psi.GroovyFile class IDEAndroidPackageFragmentProviderExtension(val project: Project) : AndroidPackageFragmentProviderExtension() { private val psiManager = PsiManager.getInstance(project) + override fun isExperimental(moduleInfo: ModuleInfo?): Boolean { + return moduleInfo?.androidExtensionsIsExperimental ?: false + } + override fun getLayoutXmlFileManager(project: Project, moduleInfo: ModuleInfo?): AndroidLayoutXmlFileManager? { val moduleSourceInfo = moduleInfo as? ModuleSourceInfo ?: return null val module = moduleSourceInfo.module diff --git a/plugins/plugins-tests/tests/org/jetbrains/kotlin/android/synthetic/test/CompilerTestUtils.kt b/plugins/plugins-tests/tests/org/jetbrains/kotlin/android/synthetic/test/CompilerTestUtils.kt index ab91d2fddb6..5515bbd98b8 100755 --- a/plugins/plugins-tests/tests/org/jetbrains/kotlin/android/synthetic/test/CompilerTestUtils.kt +++ b/plugins/plugins-tests/tests/org/jetbrains/kotlin/android/synthetic/test/CompilerTestUtils.kt @@ -19,8 +19,8 @@ package org.jetbrains.kotlin.android.synthetic.test import com.intellij.testFramework.registerServiceInstance import org.jetbrains.kotlin.android.synthetic.AndroidConfigurationKeys import org.jetbrains.kotlin.android.synthetic.AndroidExtensionPropertiesComponentContainerContributor -import org.jetbrains.kotlin.android.synthetic.codegen.AndroidExpressionCodegenExtension import org.jetbrains.kotlin.android.synthetic.codegen.AndroidOnDestroyClassBuilderInterceptorExtension +import org.jetbrains.kotlin.android.synthetic.codegen.CliAndroidExtensionsExpressionCodegenExtension import org.jetbrains.kotlin.android.synthetic.res.AndroidLayoutXmlFileManager import org.jetbrains.kotlin.android.synthetic.res.AndroidVariant import org.jetbrains.kotlin.android.synthetic.res.CliAndroidLayoutXmlFileManager @@ -46,10 +46,10 @@ fun KtUsefulTestCase.createTestEnvironment(configuration: CompilerConfiguration, val variants = listOf(AndroidVariant.createMainVariant(resDirectories)) project.registerServiceInstance(AndroidLayoutXmlFileManager::class.java, CliAndroidLayoutXmlFileManager(project, "test", variants)) - ExpressionCodegenExtension.registerExtension(project, AndroidExpressionCodegenExtension()) + ExpressionCodegenExtension.registerExtension(project, CliAndroidExtensionsExpressionCodegenExtension(true)) StorageComponentContainerContributor.registerExtension(project, AndroidExtensionPropertiesComponentContainerContributor()) ClassBuilderInterceptorExtension.registerExtension(project, AndroidOnDestroyClassBuilderInterceptorExtension()) - PackageFragmentProviderExtension.registerExtension(project, CliAndroidPackageFragmentProviderExtension()) + PackageFragmentProviderExtension.registerExtension(project, CliAndroidPackageFragmentProviderExtension(true)) addAndroidExtensionsRuntimeLibrary(myEnvironment)