Android Extensions: put new functionality under the flag
This commit is contained in:
@@ -3,5 +3,6 @@ error: required plugin option not present: org.jetbrains.kotlin.android:variant
|
|||||||
Plugin "org.jetbrains.kotlin.android" usage:
|
Plugin "org.jetbrains.kotlin.android" usage:
|
||||||
variant <name;path> Android build variant (required, multiple)
|
variant <name;path> Android build variant (required, multiple)
|
||||||
package <fq name> Application package (required)
|
package <fq name> Application package (required)
|
||||||
|
experimental true/false Enable experimental features
|
||||||
|
|
||||||
COMPILATION_ERROR
|
COMPILATION_ERROR
|
||||||
@@ -66,14 +66,19 @@
|
|||||||
<externalProjectDataService implementation="org.jetbrains.kotlin.android.configure.KotlinAndroidGradleLibraryDataService"/>
|
<externalProjectDataService implementation="org.jetbrains.kotlin.android.configure.KotlinAndroidGradleLibraryDataService"/>
|
||||||
</extensions>
|
</extensions>
|
||||||
|
|
||||||
|
<extensions defaultExtensionNs="org.jetbrains.plugins.gradle">
|
||||||
|
<projectResolve implementation="org.jetbrains.kotlin.android.synthetic.idea.AndroidExtensionsProjectResolverExtension"/>
|
||||||
|
</extensions>
|
||||||
|
|
||||||
<extensions defaultExtensionNs="org.jetbrains.kotlin">
|
<extensions defaultExtensionNs="org.jetbrains.kotlin">
|
||||||
<expressionCodegenExtension implementation="org.jetbrains.kotlin.android.synthetic.codegen.AndroidExpressionCodegenExtension"/>
|
<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.codegen.AndroidOnDestroyClassBuilderInterceptorExtension"/>
|
||||||
<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"/>
|
||||||
|
<gradleProjectImportHandler implementation="org.jetbrains.kotlin.android.synthetic.idea.AndroidExtensionsGradleImportHandler"/>
|
||||||
|
|
||||||
<quickFixContributor implementation="org.jetbrains.kotlin.android.quickfix.AndroidQuickFixRegistrar"/>
|
<quickFixContributor implementation="org.jetbrains.kotlin.android.quickfix.AndroidQuickFixRegistrar"/>
|
||||||
<projectConfigurator implementation="org.jetbrains.kotlin.android.configure.KotlinAndroidGradleModuleConfigurator"/>
|
<projectConfigurator implementation="org.jetbrains.kotlin.android.configure.KotlinAndroidGradleModuleConfigurator"/>
|
||||||
|
|||||||
+21
@@ -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
|
||||||
|
}
|
||||||
+46
-2
@@ -29,15 +29,17 @@ import org.gradle.api.tasks.SourceSet
|
|||||||
import org.gradle.api.tasks.compile.AbstractCompile
|
import org.gradle.api.tasks.compile.AbstractCompile
|
||||||
import org.jetbrains.kotlin.com.intellij.openapi.util.text.StringUtil.*
|
import org.jetbrains.kotlin.com.intellij.openapi.util.text.StringUtil.*
|
||||||
import org.jetbrains.kotlin.gradle.plugin.*
|
import org.jetbrains.kotlin.gradle.plugin.*
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.android.AndroidGradleWrapper
|
||||||
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
|
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
|
||||||
import org.w3c.dom.Document
|
import org.w3c.dom.Document
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import javax.xml.parsers.DocumentBuilderFactory
|
import javax.xml.parsers.DocumentBuilderFactory
|
||||||
|
|
||||||
// Use apply plugin: 'kotlin-android-extensions' to enable Android Extensions in an Android project.
|
// Use apply plugin: 'kotlin-android-extensions' to enable Android Extensions in an Android project.
|
||||||
// Just a marker plugin.
|
|
||||||
class AndroidExtensionsSubpluginIndicator : Plugin<Project> {
|
class AndroidExtensionsSubpluginIndicator : Plugin<Project> {
|
||||||
override fun apply(project: Project) {
|
override fun apply(project: Project) {
|
||||||
|
project.extensions.create("androidExtensions", AndroidExtensionsExtension::class.java)
|
||||||
|
|
||||||
val kotlinPluginWrapper = project.plugins.findPlugin(KotlinAndroidPluginWrapper::class.java) ?: run {
|
val kotlinPluginWrapper = project.plugins.findPlugin(KotlinAndroidPluginWrapper::class.java) ?: run {
|
||||||
project.logger.error("'kotlin-android' plugin should be enabled before 'kotlin-android-extensions'")
|
project.logger.error("'kotlin-android' plugin should be enabled before 'kotlin-android-extensions'")
|
||||||
return
|
return
|
||||||
@@ -83,13 +85,55 @@ class AndroidSubplugin : KotlinGradleSubplugin<KotlinCompile> {
|
|||||||
variantData: Any?,
|
variantData: Any?,
|
||||||
androidProjectHandler: Any?,
|
androidProjectHandler: Any?,
|
||||||
javaSourceSet: SourceSet?
|
javaSourceSet: SourceSet?
|
||||||
|
): List<SubpluginOption> {
|
||||||
|
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<SubpluginOption>()
|
||||||
|
|
||||||
|
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<SubpluginOption> {
|
): List<SubpluginOption> {
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
androidProjectHandler as? AbstractAndroidProjectHandler<Any?> ?: return emptyList()
|
androidProjectHandler as? AbstractAndroidProjectHandler<Any?> ?: return emptyList()
|
||||||
|
|
||||||
val androidExtension = project.extensions.getByName("android") as? BaseExtension ?: return emptyList()
|
|
||||||
val pluginOptions = arrayListOf<SubpluginOption>()
|
val pluginOptions = arrayListOf<SubpluginOption>()
|
||||||
|
|
||||||
|
pluginOptions += SubpluginOption("experimental", "true")
|
||||||
|
|
||||||
val mainSourceSet = androidExtension.sourceSets.getByName("main")
|
val mainSourceSet = androidExtension.sourceSets.getByName("main")
|
||||||
pluginOptions += SubpluginOption("package", getApplicationPackage(project, mainSourceSet))
|
pluginOptions += SubpluginOption("package", getApplicationPackage(project, mainSourceSet))
|
||||||
|
|
||||||
|
|||||||
+11
-5
@@ -18,8 +18,8 @@ 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 org.jetbrains.kotlin.android.synthetic.codegen.AndroidExpressionCodegenExtension
|
|
||||||
import org.jetbrains.kotlin.android.synthetic.codegen.AndroidOnDestroyClassBuilderInterceptorExtension
|
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.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
|
||||||
@@ -45,6 +45,7 @@ import org.jetbrains.kotlin.resolve.jvm.platform.JvmPlatform
|
|||||||
object AndroidConfigurationKeys {
|
object AndroidConfigurationKeys {
|
||||||
val VARIANT: CompilerConfigurationKey<List<String>> = CompilerConfigurationKey.create<List<String>>("Android build variant")
|
val VARIANT: CompilerConfigurationKey<List<String>> = CompilerConfigurationKey.create<List<String>>("Android build variant")
|
||||||
val PACKAGE: CompilerConfigurationKey<String> = CompilerConfigurationKey.create<String>("application package fq name")
|
val PACKAGE: CompilerConfigurationKey<String> = CompilerConfigurationKey.create<String>("application package fq name")
|
||||||
|
val EXPERIMENTAL: CompilerConfigurationKey<String> = CompilerConfigurationKey.create<String>("enable experimental features")
|
||||||
}
|
}
|
||||||
|
|
||||||
class AndroidCommandLineProcessor : CommandLineProcessor {
|
class AndroidCommandLineProcessor : CommandLineProcessor {
|
||||||
@@ -53,36 +54,41 @@ class AndroidCommandLineProcessor : CommandLineProcessor {
|
|||||||
|
|
||||||
val VARIANT_OPTION: CliOption = CliOption("variant", "<name;path>", "Android build variant", allowMultipleOccurrences = true)
|
val VARIANT_OPTION: CliOption = CliOption("variant", "<name;path>", "Android build variant", allowMultipleOccurrences = true)
|
||||||
val PACKAGE_OPTION: CliOption = CliOption("package", "<fq name>", "Application package")
|
val PACKAGE_OPTION: CliOption = CliOption("package", "<fq name>", "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 pluginId: String = ANDROID_COMPILER_PLUGIN_ID
|
||||||
|
|
||||||
override val pluginOptions: Collection<CliOption> = listOf(VARIANT_OPTION, PACKAGE_OPTION)
|
override val pluginOptions: Collection<CliOption> = listOf(VARIANT_OPTION, PACKAGE_OPTION, EXPERIMENTAL_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)
|
||||||
else -> throw CliOptionProcessingException("Unknown option: ${option.name}")
|
else -> throw CliOptionProcessingException("Unknown option: ${option.name}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class AndroidComponentRegistrar : ComponentRegistrar {
|
class AndroidComponentRegistrar : ComponentRegistrar {
|
||||||
|
|
||||||
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"
|
||||||
|
|
||||||
if (variants.isNotEmpty() && !applicationPackage.isNullOrBlank()) {
|
if (variants.isNotEmpty() && !applicationPackage.isNullOrBlank()) {
|
||||||
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, AndroidExpressionCodegenExtension())
|
ExpressionCodegenExtension.registerExtension(project, CliAndroidExtensionsExpressionCodegenExtension(isExperimental))
|
||||||
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, AndroidOnDestroyClassBuilderInterceptorExtension())
|
||||||
PackageFragmentProviderExtension.registerExtension(project, CliAndroidPackageFragmentProviderExtension())
|
PackageFragmentProviderExtension.registerExtension(project, CliAndroidPackageFragmentProviderExtension(isExperimental))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+12
-4
@@ -18,6 +18,7 @@ package org.jetbrains.kotlin.android.synthetic.codegen
|
|||||||
|
|
||||||
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.descriptors.ContainerOptionsProxy
|
import org.jetbrains.kotlin.android.synthetic.descriptors.ContainerOptionsProxy
|
||||||
import org.jetbrains.kotlin.android.synthetic.descriptors.AndroidSyntheticPackageFragmentDescriptor
|
import org.jetbrains.kotlin.android.synthetic.descriptors.AndroidSyntheticPackageFragmentDescriptor
|
||||||
import org.jetbrains.kotlin.android.synthetic.res.AndroidSyntheticFunction
|
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.extensions.ExpressionCodegenExtension
|
||||||
import org.jetbrains.kotlin.codegen.state.GenerationState
|
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.KtClassOrObject
|
import org.jetbrains.kotlin.psi.KtClassOrObject
|
||||||
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
|
||||||
@@ -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.Type
|
||||||
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
|
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
|
||||||
|
|
||||||
class AndroidExpressionCodegenExtension : ExpressionCodegenExtension {
|
abstract class AbstractAndroidExtensionsExpressionCodegenExtension : ExpressionCodegenExtension {
|
||||||
companion object {
|
companion object {
|
||||||
val PROPERTY_NAME = "_\$_findViewCache"
|
val PROPERTY_NAME = "_\$_findViewCache"
|
||||||
val CACHED_FIND_VIEW_BY_ID_METHOD_NAME = "_\$_findCachedViewById"
|
val CACHED_FIND_VIEW_BY_ID_METHOD_NAME = "_\$_findCachedViewById"
|
||||||
@@ -61,6 +63,8 @@ class AndroidExpressionCodegenExtension : ExpressionCodegenExtension {
|
|||||||
val classOrObject: KtClassOrObject,
|
val classOrObject: KtClassOrObject,
|
||||||
val containerOptions: ContainerOptionsProxy)
|
val containerOptions: ContainerOptionsProxy)
|
||||||
|
|
||||||
|
protected abstract fun isExperimental(clazz: KtClassOrObject): Boolean
|
||||||
|
|
||||||
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
|
||||||
return if (resultingDescriptor is PropertyDescriptor) {
|
return if (resultingDescriptor is PropertyDescriptor) {
|
||||||
@@ -124,7 +128,7 @@ class AndroidExpressionCodegenExtension : ExpressionCodegenExtension {
|
|||||||
|
|
||||||
override fun generateClassSyntheticParts(codegen: ImplementationBodyCodegen) {
|
override fun generateClassSyntheticParts(codegen: ImplementationBodyCodegen) {
|
||||||
val classBuilder = codegen.v
|
val classBuilder = codegen.v
|
||||||
val targetClass = codegen.myClass as? KtClassOrObject ?: return
|
val targetClass = codegen.myClass as? KtClass ?: return
|
||||||
|
|
||||||
val container = codegen.descriptor
|
val container = codegen.descriptor
|
||||||
if (container.kind != ClassKind.CLASS || container.isInner || DescriptorUtils.isLocal(container)) return
|
if (container.kind != ClassKind.CLASS || container.isInner || DescriptorUtils.isLocal(container)) return
|
||||||
@@ -132,6 +136,10 @@ class AndroidExpressionCodegenExtension : ExpressionCodegenExtension {
|
|||||||
val containerOptions = ContainerOptionsProxy.create(container)
|
val containerOptions = ContainerOptionsProxy.create(container)
|
||||||
if (containerOptions.cache == NO_CACHE) return
|
if (containerOptions.cache == NO_CACHE) return
|
||||||
|
|
||||||
|
if (containerOptions.containerType == LAYOUT_CONTAINER && !isExperimental(targetClass)) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
val context = SyntheticPartsGenerateContext(classBuilder, codegen.state, container, targetClass, containerOptions)
|
val context = SyntheticPartsGenerateContext(classBuilder, codegen.state, container, targetClass, containerOptions)
|
||||||
context.generateCachedFindViewByIdFunction()
|
context.generateCachedFindViewByIdFunction()
|
||||||
context.generateClearCacheFunction()
|
context.generateClearCacheFunction()
|
||||||
@@ -239,8 +247,8 @@ class AndroidExpressionCodegenExtension : ExpressionCodegenExtension {
|
|||||||
loadId()
|
loadId()
|
||||||
iv.invokevirtual(containerType.internalClassName, "findViewById", "(I)Landroid/view/View;", false)
|
iv.invokevirtual(containerType.internalClassName, "findViewById", "(I)Landroid/view/View;", false)
|
||||||
}
|
}
|
||||||
AndroidContainerType.FRAGMENT, AndroidContainerType.SUPPORT_FRAGMENT, AndroidContainerType.LAYOUT_CONTAINER -> {
|
AndroidContainerType.FRAGMENT, AndroidContainerType.SUPPORT_FRAGMENT, LAYOUT_CONTAINER -> {
|
||||||
if (containerType == AndroidContainerType.LAYOUT_CONTAINER) {
|
if (containerType == LAYOUT_CONTAINER) {
|
||||||
iv.invokeinterface(containerType.internalClassName, "getContainerView", "()Landroid/view/View;")
|
iv.invokeinterface(containerType.internalClassName, "getContainerView", "()Landroid/view/View;")
|
||||||
} else {
|
} else {
|
||||||
iv.invokevirtual(containerType.internalClassName, "getView", "()Landroid/view/View;", false)
|
iv.invokevirtual(containerType.internalClassName, "getView", "()Landroid/view/View;", false)
|
||||||
+4
-2
@@ -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 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
|
||||||
import org.jetbrains.kotlin.codegen.ClassBuilderFactory
|
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.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
|
||||||
|
|
||||||
class AndroidOnDestroyClassBuilderInterceptorExtension : ClassBuilderInterceptorExtension {
|
class AndroidOnDestroyClassBuilderInterceptorExtension : ClassBuilderInterceptorExtension {
|
||||||
|
|
||||||
@@ -106,7 +108,7 @@ class AndroidOnDestroyClassBuilderInterceptorExtension : ClassBuilderInterceptor
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun generateClearCacheMethodCall() {
|
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.getArgumentTypes(desc).isNotEmpty()) return
|
||||||
if (Type.getReturnType(desc) != Type.VOID_TYPE) return
|
if (Type.getReturnType(desc) != Type.VOID_TYPE) return
|
||||||
|
|
||||||
@@ -118,7 +120,7 @@ class AndroidOnDestroyClassBuilderInterceptorExtension : ClassBuilderInterceptor
|
|||||||
|
|
||||||
val iv = InstructionAdapter(this)
|
val iv = InstructionAdapter(this)
|
||||||
iv.load(0, containerType)
|
iv.load(0, containerType)
|
||||||
iv.invokevirtual(currentClassName, AndroidExpressionCodegenExtension.CLEAR_CACHE_METHOD_NAME, "()V", false)
|
iv.invokevirtual(currentClassName, CLEAR_CACHE_METHOD_NAME, "()V", false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+5
-4
@@ -20,6 +20,7 @@ import kotlinx.android.extensions.CacheImplementation
|
|||||||
import org.jetbrains.kotlin.android.synthetic.descriptors.ContainerOptionsProxy
|
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
|
||||||
|
|
||||||
interface CacheMechanism {
|
interface CacheMechanism {
|
||||||
/** Push the cache object onto the stack. */
|
/** Push the cache object onto the stack. */
|
||||||
@@ -62,7 +63,7 @@ internal class HashMapCacheMechanism(
|
|||||||
) : CacheMechanism {
|
) : CacheMechanism {
|
||||||
override fun loadCache() {
|
override fun loadCache() {
|
||||||
iv.load(0, containerType)
|
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() {
|
override fun initCache() {
|
||||||
@@ -70,7 +71,7 @@ internal class HashMapCacheMechanism(
|
|||||||
iv.anew(Type.getType("Ljava/util/HashMap;"))
|
iv.anew(Type.getType("Ljava/util/HashMap;"))
|
||||||
iv.dup()
|
iv.dup()
|
||||||
iv.invokespecial("java/util/HashMap", "<init>", "()V", false)
|
iv.invokespecial("java/util/HashMap", "<init>", "()V", false)
|
||||||
iv.putfield(containerType.internalName, AndroidExpressionCodegenExtension.PROPERTY_NAME, "Ljava/util/HashMap;")
|
iv.putfield(containerType.internalName, PROPERTY_NAME, "Ljava/util/HashMap;")
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun clearCache() {
|
override fun clearCache() {
|
||||||
@@ -96,7 +97,7 @@ internal class SparseArrayCacheMechanism(
|
|||||||
) : CacheMechanism {
|
) : CacheMechanism {
|
||||||
override fun loadCache() {
|
override fun loadCache() {
|
||||||
iv.load(0, containerType)
|
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() {
|
override fun initCache() {
|
||||||
@@ -104,7 +105,7 @@ internal class SparseArrayCacheMechanism(
|
|||||||
iv.anew(Type.getType("Landroid/util/SparseArray;"))
|
iv.anew(Type.getType("Landroid/util/SparseArray;"))
|
||||||
iv.dup()
|
iv.dup()
|
||||||
iv.invokespecial("android/util/SparseArray", "<init>", "()V", false)
|
iv.invokespecial("android/util/SparseArray", "<init>", "()V", false)
|
||||||
iv.putfield(containerType.internalName, AndroidExpressionCodegenExtension.PROPERTY_NAME, "Landroid/util/SparseArray;")
|
iv.putfield(containerType.internalName, PROPERTY_NAME, "Landroid/util/SparseArray;")
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun clearCache() {
|
override fun clearCache() {
|
||||||
|
|||||||
+23
@@ -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
|
||||||
|
}
|
||||||
+3
-2
@@ -17,7 +17,8 @@
|
|||||||
package org.jetbrains.kotlin.android.synthetic.codegen
|
package org.jetbrains.kotlin.android.synthetic.codegen
|
||||||
|
|
||||||
import org.jetbrains.kotlin.android.synthetic.AndroidConst
|
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.descriptors.ContainerOptionsProxy
|
||||||
import org.jetbrains.kotlin.android.synthetic.res.AndroidSyntheticProperty
|
import org.jetbrains.kotlin.android.synthetic.res.AndroidSyntheticProperty
|
||||||
import org.jetbrains.kotlin.codegen.StackValue
|
import org.jetbrains.kotlin.codegen.StackValue
|
||||||
@@ -58,7 +59,7 @@ class ResourcePropertyStackValue(
|
|||||||
val packageName = resourceId.packageName ?: androidPackage
|
val packageName = resourceId.packageName ?: androidPackage
|
||||||
v.getstatic(packageName.replace(".", "/") + "/R\$id", resourceId.name, "I")
|
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 {
|
else {
|
||||||
when (containerType) {
|
when (containerType) {
|
||||||
|
|||||||
+3
-2
@@ -42,7 +42,8 @@ class AndroidSyntheticPackageFragmentDescriptor(
|
|||||||
fqName: FqName,
|
fqName: FqName,
|
||||||
val packageData: AndroidSyntheticPackageData,
|
val packageData: AndroidSyntheticPackageData,
|
||||||
private val lazyContext: LazySyntheticElementResolveContext,
|
private val lazyContext: LazySyntheticElementResolveContext,
|
||||||
private val storageManager: StorageManager
|
private val storageManager: StorageManager,
|
||||||
|
private val isExperimental: Boolean
|
||||||
) : PackageFragmentDescriptorImpl(module, fqName) {
|
) : PackageFragmentDescriptorImpl(module, fqName) {
|
||||||
private val scope = AndroidExtensionPropertiesScope()
|
private val scope = AndroidExtensionPropertiesScope()
|
||||||
override fun getMemberScope(): MemberScope = scope
|
override fun getMemberScope(): MemberScope = scope
|
||||||
@@ -52,7 +53,7 @@ class AndroidSyntheticPackageFragmentDescriptor(
|
|||||||
val packageFragmentDescriptor = this@AndroidSyntheticPackageFragmentDescriptor
|
val packageFragmentDescriptor = this@AndroidSyntheticPackageFragmentDescriptor
|
||||||
|
|
||||||
val context = lazyContext()
|
val context = lazyContext()
|
||||||
val widgetReceivers = context.getWidgetReceivers(packageData.forView)
|
val widgetReceivers = context.getWidgetReceivers(packageData.forView, isExperimental)
|
||||||
val fragmentTypes = context.fragmentTypes
|
val fragmentTypes = context.fragmentTypes
|
||||||
|
|
||||||
val properties = ArrayList<PropertyDescriptor>(0)
|
val properties = ArrayList<PropertyDescriptor>(0)
|
||||||
|
|||||||
+7
-2
@@ -77,6 +77,11 @@ internal class SyntheticElementResolveContext(
|
|||||||
receivers += WidgetReceiver(dialog, mayHaveCache = false)
|
receivers += WidgetReceiver(dialog, mayHaveCache = false)
|
||||||
fragment?.let { receivers += WidgetReceiver(it, mayHaveCache = true) }
|
fragment?.let { receivers += WidgetReceiver(it, mayHaveCache = true) }
|
||||||
supportFragment?.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) }
|
layoutContainer?.let { receivers += WidgetReceiver(it, mayHaveCache = true) }
|
||||||
receivers
|
receivers
|
||||||
}
|
}
|
||||||
@@ -97,9 +102,9 @@ internal class SyntheticElementResolveContext(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getWidgetReceivers(forView: Boolean): List<WidgetReceiver> {
|
fun getWidgetReceivers(forView: Boolean, isExperimental: Boolean): List<WidgetReceiver> {
|
||||||
if (forView) return listOf(WidgetReceiver(view, mayHaveCache = true))
|
if (forView) return listOf(WidgetReceiver(view, mayHaveCache = true))
|
||||||
return widgetReceivers
|
return if (isExperimental) experimentalWidgetReceivers else widgetReceivers
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+9
-2
@@ -31,6 +31,8 @@ import org.jetbrains.kotlin.storage.StorageManager
|
|||||||
abstract class AndroidPackageFragmentProviderExtension : PackageFragmentProviderExtension {
|
abstract class AndroidPackageFragmentProviderExtension : PackageFragmentProviderExtension {
|
||||||
protected abstract fun getLayoutXmlFileManager(project: Project, moduleInfo: ModuleInfo?): AndroidLayoutXmlFileManager?
|
protected abstract fun getLayoutXmlFileManager(project: Project, moduleInfo: ModuleInfo?): AndroidLayoutXmlFileManager?
|
||||||
|
|
||||||
|
protected abstract fun isExperimental(moduleInfo: ModuleInfo?): Boolean
|
||||||
|
|
||||||
override fun getPackageFragmentProvider(
|
override fun getPackageFragmentProvider(
|
||||||
project: Project,
|
project: Project,
|
||||||
module: ModuleDescriptor,
|
module: ModuleDescriptor,
|
||||||
@@ -38,6 +40,8 @@ abstract class AndroidPackageFragmentProviderExtension : PackageFragmentProvider
|
|||||||
trace: BindingTrace,
|
trace: BindingTrace,
|
||||||
moduleInfo: ModuleInfo?
|
moduleInfo: ModuleInfo?
|
||||||
): PackageFragmentProvider? {
|
): PackageFragmentProvider? {
|
||||||
|
val isExperimental = isExperimental(moduleInfo)
|
||||||
|
|
||||||
val layoutXmlFileManager = getLayoutXmlFileManager(project, moduleInfo) ?: return null
|
val layoutXmlFileManager = getLayoutXmlFileManager(project, moduleInfo) ?: return null
|
||||||
|
|
||||||
val moduleData = layoutXmlFileManager.getModuleData()
|
val moduleData = layoutXmlFileManager.getModuleData()
|
||||||
@@ -54,7 +58,7 @@ abstract class AndroidPackageFragmentProviderExtension : PackageFragmentProvider
|
|||||||
val resources = layoutXmlFileManager.extractResources(AndroidLayoutGroupData(layoutName, layouts), module)
|
val resources = layoutXmlFileManager.extractResources(AndroidLayoutGroupData(layoutName, layouts), module)
|
||||||
val packageData = AndroidSyntheticPackageData(moduleData, forView, isDeprecated, resources)
|
val packageData = AndroidSyntheticPackageData(moduleData, forView, isDeprecated, resources)
|
||||||
val packageDescriptor = AndroidSyntheticPackageFragmentDescriptor(
|
val packageDescriptor = AndroidSyntheticPackageFragmentDescriptor(
|
||||||
module, FqName(fqName), packageData, lazyContext, storageManager)
|
module, FqName(fqName), packageData, lazyContext, storageManager, isExperimental)
|
||||||
packagesToLookupInCompletion += packageDescriptor
|
packagesToLookupInCompletion += packageDescriptor
|
||||||
allPackageDescriptors += packageDescriptor
|
allPackageDescriptors += packageDescriptor
|
||||||
}
|
}
|
||||||
@@ -79,7 +83,10 @@ abstract class AndroidPackageFragmentProviderExtension : PackageFragmentProvider
|
|||||||
// Package with clearFindViewByIdCache()
|
// Package with clearFindViewByIdCache()
|
||||||
AndroidConst.SYNTHETIC_SUBPACKAGES.last().let { s ->
|
AndroidConst.SYNTHETIC_SUBPACKAGES.last().let { s ->
|
||||||
val packageDescriptor = PredefinedPackageFragmentDescriptor(s, module, storageManager, packagesToLookupInCompletion) { descriptor ->
|
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 }
|
.filter { it.mayHaveCache }
|
||||||
.map { genClearCacheFunction(descriptor, it.type) }
|
.map { genClearCacheFunction(descriptor, it.type) }
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-1
@@ -17,10 +17,13 @@
|
|||||||
package org.jetbrains.kotlin.android.synthetic.res
|
package org.jetbrains.kotlin.android.synthetic.res
|
||||||
|
|
||||||
import com.intellij.openapi.components.ServiceManager
|
import com.intellij.openapi.components.ServiceManager
|
||||||
|
import com.intellij.openapi.module.Module
|
||||||
import com.intellij.openapi.project.Project
|
import com.intellij.openapi.project.Project
|
||||||
import org.jetbrains.kotlin.analyzer.ModuleInfo
|
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? {
|
override fun getLayoutXmlFileManager(project: Project, moduleInfo: ModuleInfo?): AndroidLayoutXmlFileManager? {
|
||||||
return ServiceManager.getService(project, AndroidLayoutXmlFileManager::class.java)
|
return ServiceManager.getService(project, AndroidLayoutXmlFileManager::class.java)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,5 +22,8 @@
|
|||||||
<orderEntry type="module" module-name="frontend.java" scope="TEST" />
|
<orderEntry type="module" module-name="frontend.java" scope="TEST" />
|
||||||
<orderEntry type="module" module-name="idea-live-templates" scope="TEST" />
|
<orderEntry type="module" module-name="idea-live-templates" scope="TEST" />
|
||||||
<orderEntry type="library" name="gradle-and-groovy-plugin" level="project" />
|
<orderEntry type="library" name="gradle-and-groovy-plugin" level="project" />
|
||||||
|
<orderEntry type="module" module-name="idea-jps-common" />
|
||||||
|
<orderEntry type="module" module-name="cli-common" />
|
||||||
|
<orderEntry type="module" module-name="backend" />
|
||||||
</component>
|
</component>
|
||||||
</module>
|
</module>
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
org.jetbrains.kotlin.android.synthetic.idea.AndroidExtensionsModelBuilderService
|
||||||
+121
@@ -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<ModuleData>.hasAndroidExtensionsPlugin: Boolean
|
||||||
|
by NotNullableUserDataProperty(Key.create<Boolean>("HAS_ANDROID_EXTENSIONS_PLUGIN"), false)
|
||||||
|
|
||||||
|
var DataNode<ModuleData>.isExperimental: Boolean
|
||||||
|
by NotNullableUserDataProperty(Key.create<Boolean>("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<ModuleData>) {
|
||||||
|
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<GradleSourceSetData>) {
|
||||||
|
val module = ExternalSystemApiUtil.findParent(sourceSetNode, ProjectKeys.MODULE) ?: return
|
||||||
|
importByModule(facet, module)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun importByModule(facet: KotlinFacet, moduleNode: DataNode<ModuleData>) {
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
+38
@@ -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"
|
||||||
|
}
|
||||||
+28
@@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
+9
@@ -25,14 +25,23 @@ import com.intellij.openapi.project.Project
|
|||||||
import com.intellij.psi.PsiManager
|
import com.intellij.psi.PsiManager
|
||||||
import org.jetbrains.android.facet.AndroidFacet
|
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.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.AndroidLayoutXmlFileManager
|
||||||
import org.jetbrains.kotlin.android.synthetic.res.AndroidPackageFragmentProviderExtension
|
import org.jetbrains.kotlin.android.synthetic.res.AndroidPackageFragmentProviderExtension
|
||||||
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.plugins.groovy.lang.psi.GroovyFile
|
import org.jetbrains.plugins.groovy.lang.psi.GroovyFile
|
||||||
|
|
||||||
class IDEAndroidPackageFragmentProviderExtension(val project: Project) : AndroidPackageFragmentProviderExtension() {
|
class IDEAndroidPackageFragmentProviderExtension(val project: Project) : AndroidPackageFragmentProviderExtension() {
|
||||||
private val psiManager = PsiManager.getInstance(project)
|
private val psiManager = PsiManager.getInstance(project)
|
||||||
|
|
||||||
|
override fun isExperimental(moduleInfo: ModuleInfo?): Boolean {
|
||||||
|
return moduleInfo?.androidExtensionsIsExperimental ?: false
|
||||||
|
}
|
||||||
|
|
||||||
override fun getLayoutXmlFileManager(project: Project, moduleInfo: ModuleInfo?): AndroidLayoutXmlFileManager? {
|
override fun getLayoutXmlFileManager(project: Project, moduleInfo: ModuleInfo?): AndroidLayoutXmlFileManager? {
|
||||||
val moduleSourceInfo = moduleInfo as? ModuleSourceInfo ?: return null
|
val moduleSourceInfo = moduleInfo as? ModuleSourceInfo ?: return null
|
||||||
val module = moduleSourceInfo.module
|
val module = moduleSourceInfo.module
|
||||||
|
|||||||
+3
-3
@@ -19,8 +19,8 @@ package org.jetbrains.kotlin.android.synthetic.test
|
|||||||
import com.intellij.testFramework.registerServiceInstance
|
import com.intellij.testFramework.registerServiceInstance
|
||||||
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.AndroidExpressionCodegenExtension
|
|
||||||
import org.jetbrains.kotlin.android.synthetic.codegen.AndroidOnDestroyClassBuilderInterceptorExtension
|
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.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,10 +46,10 @@ 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, AndroidExpressionCodegenExtension())
|
ExpressionCodegenExtension.registerExtension(project, CliAndroidExtensionsExpressionCodegenExtension(true))
|
||||||
StorageComponentContainerContributor.registerExtension(project, AndroidExtensionPropertiesComponentContainerContributor())
|
StorageComponentContainerContributor.registerExtension(project, AndroidExtensionPropertiesComponentContainerContributor())
|
||||||
ClassBuilderInterceptorExtension.registerExtension(project, AndroidOnDestroyClassBuilderInterceptorExtension())
|
ClassBuilderInterceptorExtension.registerExtension(project, AndroidOnDestroyClassBuilderInterceptorExtension())
|
||||||
PackageFragmentProviderExtension.registerExtension(project, CliAndroidPackageFragmentProviderExtension())
|
PackageFragmentProviderExtension.registerExtension(project, CliAndroidPackageFragmentProviderExtension(true))
|
||||||
|
|
||||||
addAndroidExtensionsRuntimeLibrary(myEnvironment)
|
addAndroidExtensionsRuntimeLibrary(myEnvironment)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user