Android Extensions: Do not upcast ViewStub to View (KT-10321)

This commit is contained in:
Yan Zhulanow
2016-03-25 17:58:56 +03:00
parent 6e14c11280
commit 371e80bcba
6 changed files with 17 additions and 19 deletions
@@ -96,7 +96,7 @@ class AndroidExpressionCodegenExtension : ExpressionCodegenExtension {
fun isCacheSupported(receiverDescriptor: ClassDescriptor, descriptor: PropertyDescriptor? = null): Boolean { fun isCacheSupported(receiverDescriptor: ClassDescriptor, descriptor: PropertyDescriptor? = null): Boolean {
val receiverIsKotlinClass = receiverDescriptor.source is KotlinSourceElement val receiverIsKotlinClass = receiverDescriptor.source is KotlinSourceElement
return receiverIsKotlinClass && when (descriptor) { return receiverIsKotlinClass && when (descriptor) {
is AndroidSyntheticProperty -> !descriptor.alwaysCastToView is AndroidSyntheticProperty -> descriptor.cacheView
else -> true else -> true
} }
} }
@@ -32,6 +32,7 @@ import org.jetbrains.kotlin.utils.Printer
import java.util.* import java.util.*
class AndroidSyntheticPackageData( class AndroidSyntheticPackageData(
val layoutName: String,
val moduleData: AndroidModuleData, val moduleData: AndroidModuleData,
val forView: Boolean, val forView: Boolean,
val isDeprecated: Boolean, val isDeprecated: Boolean,
@@ -68,7 +69,7 @@ class AndroidSyntheticPackageFragmentDescriptor(
} }
is AndroidResource.Fragment -> if (!packageData.forView) { is AndroidResource.Fragment -> if (!packageData.forView) {
for ((receiverType, type) in fragmentTypes) { for ((receiverType, type) in fragmentTypes) {
properties += genPropertyForFragment(packageFragmentDescriptor, receiverType, type, resource, context) properties += genPropertyForFragment(packageFragmentDescriptor, receiverType, type, resource)
} }
} }
} }
@@ -52,7 +52,7 @@ abstract class AndroidPackageFragmentProviderExtension : PackageFragmentProvider
for ((layoutName, layouts) in variantData) { for ((layoutName, layouts) in variantData) {
fun createPackageFragment(fqName: String, forView: Boolean, isDeprecated: Boolean = false) { fun createPackageFragment(fqName: String, forView: Boolean, isDeprecated: Boolean = false) {
val resources = layoutXmlFileManager.extractResources(layouts, module) val resources = layoutXmlFileManager.extractResources(layouts, module)
val packageData = AndroidSyntheticPackageData(moduleData, forView, isDeprecated, resources) val packageData = AndroidSyntheticPackageData(layoutName, moduleData, forView, isDeprecated, resources)
val packageDescriptor = AndroidSyntheticPackageFragmentDescriptor( val packageDescriptor = AndroidSyntheticPackageFragmentDescriptor(
module, FqName(fqName), packageData, lazyContext, storageManager) module, FqName(fqName), packageData, lazyContext, storageManager)
packagesToLookupInCompletion += packageDescriptor packagesToLookupInCompletion += packageDescriptor
@@ -66,30 +66,28 @@ internal fun genPropertyForWidget(
defaultType.constructor.parameters.map { StarProjectionImpl(it) }) defaultType.constructor.parameters.map { StarProjectionImpl(it) })
} ?: context.viewType } ?: context.viewType
return genProperty(resolvedWidget.widget.id, receiverType, type, packageFragmentDescriptor, sourceEl, context, resolvedWidget.errorType) return genProperty(resolvedWidget.widget.id, receiverType, type, packageFragmentDescriptor, sourceEl, resolvedWidget.errorType)
} }
internal fun genPropertyForFragment( internal fun genPropertyForFragment(
packageFragmentDescriptor: PackageFragmentDescriptor, packageFragmentDescriptor: AndroidSyntheticPackageFragmentDescriptor,
receiverType: KotlinType, receiverType: KotlinType,
type: KotlinType, type: KotlinType,
fragment: AndroidResource.Fragment, fragment: AndroidResource.Fragment
context: SyntheticElementResolveContext
): PropertyDescriptor { ): PropertyDescriptor {
val sourceElement = fragment.sourceElement?.let { XmlSourceElement(it) } ?: SourceElement.NO_SOURCE val sourceElement = fragment.sourceElement?.let { XmlSourceElement(it) } ?: SourceElement.NO_SOURCE
return genProperty(fragment.id, receiverType, type, packageFragmentDescriptor, sourceElement, context, null) return genProperty(fragment.id, receiverType, type, packageFragmentDescriptor, sourceElement, null)
} }
private fun genProperty( private fun genProperty(
id: ResourceIdentifier, id: ResourceIdentifier,
receiverType: KotlinType, receiverType: KotlinType,
type: KotlinType, type: KotlinType,
containingDeclaration: DeclarationDescriptor, containingDeclaration: AndroidSyntheticPackageFragmentDescriptor,
sourceElement: SourceElement, sourceElement: SourceElement,
context: SyntheticElementResolveContext,
errorType: String? errorType: String?
): PropertyDescriptor { ): PropertyDescriptor {
val alwaysCastToView = type.constructor.declarationDescriptor?.fqNameUnsafe?.asString() == AndroidConst.VIEWSTUB_FQNAME val cacheView = type.constructor.declarationDescriptor?.fqNameUnsafe?.asString() != AndroidConst.VIEWSTUB_FQNAME
val property = object : AndroidSyntheticProperty, PropertyDescriptorImpl( val property = object : AndroidSyntheticProperty, PropertyDescriptorImpl(
containingDeclaration, containingDeclaration,
@@ -104,12 +102,11 @@ private fun genProperty(
false, false,
false) { false) {
override val errorType = errorType override val errorType = errorType
override val alwaysCastToView = alwaysCastToView override val cacheView = cacheView
override val resourceId = id override val resourceId = id
} }
val actualType = if (alwaysCastToView) context.viewType else type val flexibleType = DelegatingFlexibleType.create(type, type.makeNullable(), FlexibleTypeCapabilities.NONE)
val flexibleType = DelegatingFlexibleType.create(actualType, actualType.makeNullable(), FlexibleTypeCapabilities.NONE)
property.setType( property.setType(
flexibleType, flexibleType,
emptyList<TypeParameterDescriptor>(), emptyList<TypeParameterDescriptor>(),
@@ -139,7 +136,7 @@ interface AndroidSyntheticFunction
interface AndroidSyntheticProperty { interface AndroidSyntheticProperty {
val errorType: String? val errorType: String?
val alwaysCastToView: Boolean val cacheView: Boolean
val resourceId: ResourceIdentifier val resourceId: ResourceIdentifier
val isErrorType: Boolean val isErrorType: Boolean
@@ -14,5 +14,5 @@ public class MyActivity : Activity() {
// 1 GETSTATIC test/R\$id\.stub // 1 GETSTATIC test/R\$id\.stub
// 0 INVOKEVIRTUAL test/MyActivity\._\$_findCachedViewById // 0 INVOKEVIRTUAL test/MyActivity\._\$_findCachedViewById
// 1 INVOKEVIRTUAL android/app/Activity\.findViewById // 1 INVOKEVIRTUAL android/app/Activity\.findViewById
// 0 CHECKCAST android/view/ViewStub // 1 CHECKCAST android/view/ViewStub
// 2 CHECKCAST android/view/View // 2 CHECKCAST android/view/View
@@ -15,10 +15,10 @@ kotlinx.android.synthetic.main
kotlinx.android.synthetic.main.test kotlinx.android.synthetic.main.test
public val android.app.Activity.stub: android.view.View! public val android.app.Activity.stub: android.view.ViewStub!
public val android.app.Fragment.stub: android.view.View! public val android.app.Fragment.stub: android.view.ViewStub!
kotlinx.android.synthetic.main.test.view kotlinx.android.synthetic.main.test.view
public val android.view.View.stub: android.view.View! public val android.view.View.stub: android.view.ViewStub!