From 4f3f813b32556f73505101e341c5ddad20d1ba62 Mon Sep 17 00:00:00 2001 From: Yan Zhulanow Date: Thu, 1 Nov 2018 16:56:03 +0900 Subject: [PATCH] Android Extensions: Make AndroidPackageFragmentProviderExtension lazy --- .../PredefinedPackageFragmentDescriptor.kt | 18 ++++- ...AndroidPackageFragmentProviderExtension.kt | 77 +++++++++++-------- ...AndroidPackageFragmentProviderExtension.kt | 1 - ...tAndroidSyntheticPropertyDescriptorTest.kt | 11 ++- .../idea/AndroidIndicesHelperExtension.kt | 8 +- 5 files changed, 72 insertions(+), 43 deletions(-) diff --git a/plugins/android-extensions/android-extensions-compiler/src/org/jetbrains/kotlin/android/synthetic/descriptors/PredefinedPackageFragmentDescriptor.kt b/plugins/android-extensions/android-extensions-compiler/src/org/jetbrains/kotlin/android/synthetic/descriptors/PredefinedPackageFragmentDescriptor.kt index 4f274800a58..ea27cf9607a 100644 --- a/plugins/android-extensions/android-extensions-compiler/src/org/jetbrains/kotlin/android/synthetic/descriptors/PredefinedPackageFragmentDescriptor.kt +++ b/plugins/android-extensions/android-extensions-compiler/src/org/jetbrains/kotlin/android/synthetic/descriptors/PredefinedPackageFragmentDescriptor.kt @@ -16,6 +16,7 @@ package org.jetbrains.kotlin.android.synthetic.descriptors +import com.intellij.openapi.util.ClearableLazyValue import org.jetbrains.kotlin.descriptors.ModuleDescriptor import org.jetbrains.kotlin.descriptors.PackageFragmentDescriptor import org.jetbrains.kotlin.descriptors.PropertyDescriptor @@ -30,16 +31,27 @@ import org.jetbrains.kotlin.storage.StorageManager import org.jetbrains.kotlin.utils.Printer class PredefinedPackageFragmentDescriptor( - fqName: String, + fqName: FqName, module: ModuleDescriptor, storageManager: StorageManager, - val subpackages: List = emptyList(), + val lazySubpackages: List = emptyList(), private val functions: (PredefinedPackageFragmentDescriptor) -> Collection = { emptyList() } -) : PackageFragmentDescriptorImpl(module, FqName(fqName)) { +) : PackageFragmentDescriptorImpl(module, fqName) { + class LazyAndroidExtensionsPackageFragmentDescriptor( + val descriptor: ClearableLazyValue, + val isDeprecated: Boolean + ) + private val calculatedFunctions = storageManager.createLazyValue { functions(this) } + // Left for compatibility with Android Studio + @Deprecated("Use lazySubpackages instead.", ReplaceWith("lazySubpackages")) + @Suppress("unused") + val subpackages: List + get() = lazySubpackages.map { it.descriptor() } + private val scope = PredefinedScope() override fun getMemberScope() = scope 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 f1153659c49..2fac1ca6c75 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 @@ -17,12 +17,14 @@ package org.jetbrains.kotlin.android.synthetic.res import com.intellij.openapi.project.Project +import com.intellij.openapi.util.ClearableLazyValue import org.jetbrains.kotlin.analyzer.ModuleInfo import org.jetbrains.kotlin.android.synthetic.AndroidConst import org.jetbrains.kotlin.android.synthetic.descriptors.AndroidSyntheticPackageData import org.jetbrains.kotlin.android.synthetic.descriptors.AndroidSyntheticPackageFragmentDescriptor import org.jetbrains.kotlin.android.synthetic.descriptors.LazySyntheticElementResolveContext import org.jetbrains.kotlin.android.synthetic.descriptors.PredefinedPackageFragmentDescriptor +import org.jetbrains.kotlin.android.synthetic.descriptors.PredefinedPackageFragmentDescriptor.LazyAndroidExtensionsPackageFragmentDescriptor import org.jetbrains.kotlin.android.synthetic.forEachUntilLast import org.jetbrains.kotlin.descriptors.ModuleDescriptor import org.jetbrains.kotlin.descriptors.PackageFragmentDescriptor @@ -55,22 +57,27 @@ abstract class AndroidPackageFragmentProviderExtension : PackageFragmentProvider val lazyContext = LazySyntheticElementResolveContext(module, storageManager) - val allPackageDescriptors = arrayListOf() - val packagesToLookupInCompletion = arrayListOf() + val packages = mutableMapOf>() + val packagesToLookupInCompletion = mutableListOf() // Packages with synthetic properties for (variantData in moduleData.variants) { for ((layoutName, layouts) in variantData.layouts) { - fun createPackageFragment(fqName: String, forView: Boolean, isDeprecated: Boolean = false) { - val packageData = AndroidSyntheticPackageData(moduleData, forView, isDeprecated) { - layoutXmlFileManager.extractResources(AndroidLayoutGroupData(layoutName, layouts), module) - } - val packageDescriptor = AndroidSyntheticPackageFragmentDescriptor( - module, FqName(fqName), packageData, lazyContext, storageManager, isExperimental, + fun createPackageFragment(fqNameString: String, forView: Boolean, isDeprecated: Boolean = false) { + val fqName = FqName(fqNameString) + + val lazyPackageDescriptor = ClearableLazyValue.create { + val packageData = AndroidSyntheticPackageData(moduleData, forView, isDeprecated) { + layoutXmlFileManager.extractResources(AndroidLayoutGroupData(layoutName, layouts), module) + } + + AndroidSyntheticPackageFragmentDescriptor( + module, fqName, packageData, lazyContext, storageManager, isExperimental, lookupTracker, layoutName - ) - packagesToLookupInCompletion += packageDescriptor - allPackageDescriptors += packageDescriptor + ) + } + packages[fqName] = lazyPackageDescriptor + packagesToLookupInCompletion += LazyAndroidExtensionsPackageFragmentDescriptor(lazyPackageDescriptor, isDeprecated) } val packageFqName = AndroidConst.SYNTHETIC_PACKAGE + '.' + variantData.variant.name + '.' + layoutName @@ -81,40 +88,50 @@ abstract class AndroidPackageFragmentProviderExtension : PackageFragmentProvider } // Empty middle packages - AndroidConst.SYNTHETIC_SUBPACKAGES.forEachUntilLast { s -> - allPackageDescriptors += PredefinedPackageFragmentDescriptor(s, module, storageManager) + AndroidConst.SYNTHETIC_SUBPACKAGES.forEachUntilLast { fqNameString -> + val fqName = FqName(fqNameString) + packages[fqName] = ClearableLazyValue.create { + PredefinedPackageFragmentDescriptor(fqName, module, storageManager) + } } for (variantData in moduleData.variants) { - val fqName = AndroidConst.SYNTHETIC_PACKAGE + '.' + variantData.variant.name - allPackageDescriptors += PredefinedPackageFragmentDescriptor(fqName, module, storageManager) + val fqName = FqName(AndroidConst.SYNTHETIC_PACKAGE + '.' + variantData.variant.name) + packages[fqName] = ClearableLazyValue.create { + PredefinedPackageFragmentDescriptor(fqName, module, storageManager) + } } // Package with clearFindViewByIdCache() - AndroidConst.SYNTHETIC_SUBPACKAGES.last().let { s -> - val packageDescriptor = PredefinedPackageFragmentDescriptor(s, module, storageManager, packagesToLookupInCompletion) { descriptor -> - val widgetReceivers = lazyContext().getWidgetReceivers(forView = false, isExperimental = isExperimental) + - lazyContext().getWidgetReceivers(forView = true, isExperimental = isExperimental) + AndroidConst.SYNTHETIC_SUBPACKAGES.last().let { fqNameString -> + val fqName = FqName(fqNameString) + val lazyPackageDescriptor = ClearableLazyValue.create { + PredefinedPackageFragmentDescriptor(fqName, module, storageManager, packagesToLookupInCompletion) { descriptor -> + val widgetReceivers = lazyContext().getWidgetReceivers(forView = false, isExperimental = isExperimental) + + lazyContext().getWidgetReceivers(forView = true, isExperimental = isExperimental) - widgetReceivers + widgetReceivers .filter { it.mayHaveCache } .map { genClearCacheFunction(descriptor, it.type) } + } } - packagesToLookupInCompletion += packageDescriptor - allPackageDescriptors += packageDescriptor + + packages[fqName] = lazyPackageDescriptor + packagesToLookupInCompletion += LazyAndroidExtensionsPackageFragmentDescriptor(lazyPackageDescriptor, false) } - return AndroidSyntheticPackageFragmentProvider(allPackageDescriptors) + return AndroidSyntheticPackageFragmentProvider(packages) } } -class AndroidSyntheticPackageFragmentProvider(val packageFragments: Collection) : PackageFragmentProvider { - override fun getPackageFragments(fqName: FqName) = packageFragments.filter { it.fqName == fqName } +class AndroidSyntheticPackageFragmentProvider( + val packages: Map> +) : PackageFragmentProvider { + override fun getPackageFragments(fqName: FqName) = listOfNotNull(packages[fqName]?.value) override fun getSubPackagesOf(fqName: FqName, nameFilter: (Name) -> Boolean): List { - return packageFragments.asSequence() - .map { it.fqName } - .filter { !it.isRoot && it.parent() == fqName } - .toList() + return packages.asSequence() + .filter { (k, _) -> !k.isRoot && k.parent() == fqName } + .mapTo(mutableListOf()) { it.key } } -} +} \ No newline at end of file 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 a785731ae28..0896c89d18c 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,7 +17,6 @@ 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 diff --git a/plugins/android-extensions/android-extensions-compiler/test/org/jetbrains/android/synthetic/test/AbstractAndroidSyntheticPropertyDescriptorTest.kt b/plugins/android-extensions/android-extensions-compiler/test/org/jetbrains/android/synthetic/test/AbstractAndroidSyntheticPropertyDescriptorTest.kt index fcb0f9c0032..ba1b097b7c0 100755 --- a/plugins/android-extensions/android-extensions-compiler/test/org/jetbrains/android/synthetic/test/AbstractAndroidSyntheticPropertyDescriptorTest.kt +++ b/plugins/android-extensions/android-extensions-compiler/test/org/jetbrains/android/synthetic/test/AbstractAndroidSyntheticPropertyDescriptorTest.kt @@ -47,12 +47,15 @@ abstract class AbstractAndroidSyntheticPropertyDescriptorTest : KtUsefulTestCase ) as AndroidSyntheticPackageFragmentProvider val renderer = DescriptorRenderer.COMPACT_WITH_MODIFIERS - val expected = fragmentProvider.packageFragments.sortedBy { it.fqName.asString() }.map { - val descriptors = it.getMemberScope().getContributedDescriptors() + val expected = fragmentProvider.packages.values + .map { it() } + .sortedBy { it.fqName.asString() } + .joinToString(separator = "\n\n\n") { + val descriptors = it.getMemberScope().getContributedDescriptors() .sortedWith(MemberComparator.INSTANCE) .map { " " + renderer.render(it) }.joinToString("\n") - it.fqName.asString() + (if (descriptors.isNotEmpty()) "\n\n" + descriptors else "") - }.joinToString("\n\n\n") + it.fqName.asString() + (if (descriptors.isNotEmpty()) "\n\n" + descriptors else "") + } KotlinTestUtils.assertEqualsToFile(File(path, "result.txt"), expected) } diff --git a/plugins/android-extensions/android-extensions-idea/src/org/jetbrains/kotlin/android/synthetic/idea/AndroidIndicesHelperExtension.kt b/plugins/android-extensions/android-extensions-idea/src/org/jetbrains/kotlin/android/synthetic/idea/AndroidIndicesHelperExtension.kt index cd99822419f..2c76f9845a0 100644 --- a/plugins/android-extensions/android-extensions-idea/src/org/jetbrains/kotlin/android/synthetic/idea/AndroidIndicesHelperExtension.kt +++ b/plugins/android-extensions/android-extensions-idea/src/org/jetbrains/kotlin/android/synthetic/idea/AndroidIndicesHelperExtension.kt @@ -17,7 +17,6 @@ package org.jetbrains.kotlin.android.synthetic.idea import org.jetbrains.kotlin.android.synthetic.AndroidConst -import org.jetbrains.kotlin.android.synthetic.descriptors.AndroidSyntheticPackageFragmentDescriptor import org.jetbrains.kotlin.android.synthetic.descriptors.PredefinedPackageFragmentDescriptor import org.jetbrains.kotlin.descriptors.CallableDescriptor import org.jetbrains.kotlin.descriptors.ModuleDescriptor @@ -29,7 +28,6 @@ import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.typeUtil.isSubtypeOf class AndroidIndicesHelperExtension : KotlinIndicesHelperExtension { - override fun appendExtensionCallables( consumer: MutableList, moduleDescriptor: ModuleDescriptor, @@ -50,9 +48,9 @@ class AndroidIndicesHelperExtension : KotlinIndicesHelperExtension { } handleScope(packageFragment.getMemberScope()) - for (fragment in packageFragment.subpackages) { - if (fragment is AndroidSyntheticPackageFragmentDescriptor && fragment.packageData.isDeprecated) continue - handleScope(fragment.getMemberScope()) + for (fragment in packageFragment.lazySubpackages) { + if (fragment.isDeprecated) continue + handleScope(fragment.descriptor().getMemberScope()) } } }