Android Extensions: Make AndroidPackageFragmentProviderExtension lazy

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