Refactoring: rename android-compiler-plugin to android-extensions-compiler
This commit is contained in:
+22
@@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="JAVA_MODULE" version="4">
|
||||
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||
<exclude-output />
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/tests" isTestSource="true" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
<orderEntry type="module" module-name="plugin-api" exported="" />
|
||||
<orderEntry type="module" module-name="frontend" exported="" />
|
||||
<orderEntry type="module" module-name="frontend.java" exported="" />
|
||||
<orderEntry type="module" module-name="cli" />
|
||||
<orderEntry type="module" module-name="util" />
|
||||
<orderEntry type="module" module-name="backend" scope="PROVIDED" />
|
||||
<orderEntry type="library" scope="TEST" name="idea-full" level="project" />
|
||||
<orderEntry type="library" scope="TEST" name="jps-test" level="project" />
|
||||
<orderEntry type="module" module-name="compiler-tests" scope="TEST" />
|
||||
<orderEntry type="library" name="intellij-core" level="project" />
|
||||
</component>
|
||||
</module>
|
||||
+1
@@ -0,0 +1 @@
|
||||
org.jetbrains.kotlin.android.synthetic.AndroidCommandLineProcessor
|
||||
+1
@@ -0,0 +1 @@
|
||||
org.jetbrains.kotlin.android.synthetic.AndroidComponentRegistrar
|
||||
+106
@@ -0,0 +1,106 @@
|
||||
/*
|
||||
* Copyright 2010-2015 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
|
||||
|
||||
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.diagnostic.AndroidExtensionPropertiesCallChecker
|
||||
import org.jetbrains.kotlin.android.synthetic.diagnostic.DefaultErrorMessagesAndroid
|
||||
import org.jetbrains.kotlin.android.synthetic.res.AndroidLayoutXmlFileManager
|
||||
import org.jetbrains.kotlin.android.synthetic.res.AndroidVariant
|
||||
import org.jetbrains.kotlin.android.synthetic.res.CliAndroidLayoutXmlFileManager
|
||||
import org.jetbrains.kotlin.android.synthetic.res.CliAndroidPackageFragmentProviderExtension
|
||||
import org.jetbrains.kotlin.codegen.extensions.ClassBuilderInterceptorExtension
|
||||
import org.jetbrains.kotlin.codegen.extensions.ExpressionCodegenExtension
|
||||
import org.jetbrains.kotlin.compiler.plugin.CliOption
|
||||
import org.jetbrains.kotlin.compiler.plugin.CliOptionProcessingException
|
||||
import org.jetbrains.kotlin.compiler.plugin.CommandLineProcessor
|
||||
import org.jetbrains.kotlin.compiler.plugin.ComponentRegistrar
|
||||
import org.jetbrains.kotlin.config.CompilerConfiguration
|
||||
import org.jetbrains.kotlin.config.CompilerConfigurationKey
|
||||
import org.jetbrains.kotlin.container.StorageComponentContainer
|
||||
import org.jetbrains.kotlin.container.useInstance
|
||||
import org.jetbrains.kotlin.diagnostics.rendering.DefaultErrorMessages
|
||||
import org.jetbrains.kotlin.extensions.StorageComponentContainerContributor
|
||||
import org.jetbrains.kotlin.resolve.TargetPlatform
|
||||
import org.jetbrains.kotlin.resolve.jvm.extensions.PackageFragmentProviderExtension
|
||||
import org.jetbrains.kotlin.resolve.jvm.platform.JvmPlatform
|
||||
|
||||
object AndroidConfigurationKeys {
|
||||
val VARIANT: CompilerConfigurationKey<List<String>> = CompilerConfigurationKey.create<List<String>>("Android build variant")
|
||||
val PACKAGE: CompilerConfigurationKey<String> = CompilerConfigurationKey.create<String>("application package fq name")
|
||||
}
|
||||
|
||||
class AndroidCommandLineProcessor : CommandLineProcessor {
|
||||
companion object {
|
||||
val ANDROID_COMPILER_PLUGIN_ID: String = "org.jetbrains.kotlin.android"
|
||||
|
||||
val VARIANT_OPTION: CliOption = CliOption("variant", "<name;path>", "Android build variant", allowMultipleOccurrences = true)
|
||||
val PACKAGE_OPTION: CliOption = CliOption("package", "<fq name>", "Application package")
|
||||
}
|
||||
|
||||
override val pluginId: String = ANDROID_COMPILER_PLUGIN_ID
|
||||
|
||||
override val pluginOptions: Collection<CliOption> = listOf(VARIANT_OPTION, PACKAGE_OPTION)
|
||||
|
||||
override fun processOption(option: CliOption, value: String, configuration: CompilerConfiguration) {
|
||||
when (option) {
|
||||
VARIANT_OPTION -> {
|
||||
val paths = configuration.getList(AndroidConfigurationKeys.VARIANT).toMutableList()
|
||||
paths.add(value)
|
||||
configuration.put(AndroidConfigurationKeys.VARIANT, paths)
|
||||
}
|
||||
PACKAGE_OPTION -> configuration.put(AndroidConfigurationKeys.PACKAGE, 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()
|
||||
|
||||
if (variants.isNotEmpty() && !applicationPackage.isNullOrBlank()) {
|
||||
val layoutXmlFileManager = CliAndroidLayoutXmlFileManager(project, applicationPackage!!, variants)
|
||||
project.registerService(AndroidLayoutXmlFileManager::class.java, layoutXmlFileManager)
|
||||
|
||||
ExpressionCodegenExtension.registerExtension(project, AndroidExpressionCodegenExtension())
|
||||
StorageComponentContainerContributor.registerExtension(project, AndroidExtensionPropertiesComponentContainerContributor())
|
||||
Extensions.getRootArea().getExtensionPoint(DefaultErrorMessages.Extension.EP_NAME).registerExtension(DefaultErrorMessagesAndroid())
|
||||
ClassBuilderInterceptorExtension.registerExtension(project, AndroidOnDestroyClassBuilderInterceptorExtension())
|
||||
PackageFragmentProviderExtension.registerExtension(project, CliAndroidPackageFragmentProviderExtension())
|
||||
}
|
||||
}
|
||||
|
||||
private fun parseVariant(s: String): AndroidVariant? {
|
||||
val parts = s.split(';')
|
||||
if (parts.size < 2) return null
|
||||
return AndroidVariant(parts[0], parts.drop(1))
|
||||
}
|
||||
}
|
||||
|
||||
class AndroidExtensionPropertiesComponentContainerContributor : StorageComponentContainerContributor {
|
||||
override fun addDeclarations(container: StorageComponentContainer, platform: TargetPlatform) {
|
||||
if (platform is JvmPlatform) {
|
||||
container.useInstance(AndroidExtensionPropertiesCallChecker())
|
||||
}
|
||||
}
|
||||
}
|
||||
+78
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Copyright 2010-2015 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
|
||||
|
||||
|
||||
object AndroidConst {
|
||||
val SYNTHETIC_PACKAGE: String = "kotlinx.android.synthetic"
|
||||
val SYNTHETIC_PACKAGE_PATH_LENGTH = SYNTHETIC_PACKAGE.count { it == '.' } + 1
|
||||
|
||||
val SYNTHETIC_SUBPACKAGES: List<String> = SYNTHETIC_PACKAGE.split('.').fold(arrayListOf<String>()) { list, segment ->
|
||||
val prevSegment = list.lastOrNull()?.let { "$it." } ?: ""
|
||||
list += "$prevSegment$segment"
|
||||
list
|
||||
}
|
||||
|
||||
val ANDROID_NAMESPACE: String = "android"
|
||||
val ID_ATTRIBUTE_NO_NAMESPACE: String = "id"
|
||||
val ID_ATTRIBUTE: String = "$ANDROID_NAMESPACE:$ID_ATTRIBUTE_NO_NAMESPACE"
|
||||
val CLASS_ATTRIBUTE_NO_NAMESPACE: String = "class"
|
||||
|
||||
val ID_DECLARATION_PREFIX = "@+id/"
|
||||
val ID_USAGE_PREFIX = "@id/"
|
||||
val XML_ID_PREFIXES = arrayOf(ID_DECLARATION_PREFIX, ID_USAGE_PREFIX)
|
||||
|
||||
val CLEAR_FUNCTION_NAME = "clearFindViewByIdCache"
|
||||
|
||||
|
||||
//TODO FqName / ClassId
|
||||
|
||||
val VIEW_FQNAME = "android.view.View"
|
||||
val VIEWSTUB_FQNAME = "android.view.ViewStub"
|
||||
|
||||
val ACTIVITY_FQNAME = "android.app.Activity"
|
||||
val FRAGMENT_FQNAME = "android.app.Fragment"
|
||||
val SUPPORT_V4_PACKAGE = "android.support.v4"
|
||||
val SUPPORT_FRAGMENT_FQNAME = "$SUPPORT_V4_PACKAGE.app.Fragment"
|
||||
val SUPPORT_FRAGMENT_ACTIVITY_FQNAME = "$SUPPORT_V4_PACKAGE.app.FragmentActivity"
|
||||
|
||||
val IGNORED_XML_WIDGET_TYPES = setOf("requestFocus", "merge", "tag", "check", "blink")
|
||||
|
||||
val FQNAME_RESOLVE_PACKAGES = listOf("android.widget", "android.webkit", "android.view")
|
||||
}
|
||||
|
||||
fun androidIdToName(id: String): String? {
|
||||
for (prefix in AndroidConst.XML_ID_PREFIXES) {
|
||||
if (id.startsWith(prefix)) {
|
||||
return id.substring(prefix.length)
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
fun isWidgetTypeIgnored(xmlType: String): Boolean {
|
||||
return (xmlType.isEmpty() || xmlType in AndroidConst.IGNORED_XML_WIDGET_TYPES)
|
||||
}
|
||||
|
||||
internal fun <T> List<T>.forEachUntilLast(operation: (T) -> Unit) {
|
||||
val lastIndex = lastIndex
|
||||
forEachIndexed { i, t ->
|
||||
if (i < lastIndex) {
|
||||
operation(t)
|
||||
}
|
||||
}
|
||||
}
|
||||
+58
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright 2010-2015 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
|
||||
|
||||
import org.xml.sax.Attributes
|
||||
import org.xml.sax.helpers.DefaultHandler
|
||||
import java.util.HashMap
|
||||
|
||||
class AndroidXmlHandler(private val elementCallback: (String, String) -> Unit) : DefaultHandler() {
|
||||
|
||||
override fun startDocument() {
|
||||
super.startDocument()
|
||||
}
|
||||
|
||||
override fun endDocument() {
|
||||
super.endDocument()
|
||||
}
|
||||
|
||||
override fun startElement(uri: String, localName: String, qName: String, attributes: Attributes) {
|
||||
if (isWidgetTypeIgnored(localName)) return
|
||||
val attributesMap = attributes.toMap()
|
||||
val idAttribute = attributesMap[AndroidConst.ID_ATTRIBUTE_NO_NAMESPACE]
|
||||
val widgetType = attributesMap[AndroidConst.CLASS_ATTRIBUTE_NO_NAMESPACE] ?: localName
|
||||
val name = idAttribute?.let { androidIdToName(idAttribute) }
|
||||
if (name != null) elementCallback(name, widgetType)
|
||||
}
|
||||
|
||||
override fun endElement(uri: String?, localName: String, qName: String) {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fun Attributes.toMap(): HashMap<String, String> {
|
||||
val res = HashMap<String, String>()
|
||||
for (index in 0..length - 1) {
|
||||
val attrName = getLocalName(index)!!
|
||||
val attrVal = getValue(index)!!
|
||||
res[attrName] = attrVal
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
|
||||
+391
@@ -0,0 +1,391 @@
|
||||
/*
|
||||
* Copyright 2010-2015 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.android.synthetic.AndroidConst
|
||||
import org.jetbrains.kotlin.android.synthetic.descriptors.AndroidSyntheticPackageFragmentDescriptor
|
||||
import org.jetbrains.kotlin.android.synthetic.res.AndroidSyntheticFunction
|
||||
import org.jetbrains.kotlin.android.synthetic.res.AndroidSyntheticProperty
|
||||
import org.jetbrains.kotlin.codegen.ClassBuilder
|
||||
import org.jetbrains.kotlin.codegen.FunctionCodegen
|
||||
import org.jetbrains.kotlin.codegen.StackValue
|
||||
import org.jetbrains.kotlin.codegen.extensions.ExpressionCodegenExtension
|
||||
import org.jetbrains.kotlin.codegen.state.GenerationState
|
||||
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.load.java.lazy.descriptors.LazyJavaClassDescriptor
|
||||
import org.jetbrains.kotlin.psi.KtClassOrObject
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassOrAny
|
||||
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin
|
||||
import org.jetbrains.kotlin.resolve.lazy.descriptors.LazyClassDescriptor
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue
|
||||
import org.jetbrains.kotlin.resolve.source.KotlinSourceElement
|
||||
import org.jetbrains.kotlin.types.lowerIfFlexible
|
||||
import org.jetbrains.org.objectweb.asm.Label
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes.ACC_PRIVATE
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes.ACC_PUBLIC
|
||||
import org.jetbrains.org.objectweb.asm.Type
|
||||
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
|
||||
|
||||
enum class AndroidClassType(className: String, val supportsCache: Boolean = false, val fragment: Boolean = false) {
|
||||
ACTIVITY(AndroidConst.ACTIVITY_FQNAME, supportsCache = true),
|
||||
FRAGMENT(AndroidConst.FRAGMENT_FQNAME, supportsCache = true, fragment = true),
|
||||
SUPPORT_FRAGMENT_ACTIVITY(AndroidConst.SUPPORT_FRAGMENT_ACTIVITY_FQNAME, supportsCache = true),
|
||||
SUPPORT_FRAGMENT(AndroidConst.SUPPORT_FRAGMENT_FQNAME, supportsCache = true, fragment = true),
|
||||
VIEW(AndroidConst.VIEW_FQNAME),
|
||||
UNKNOWN("");
|
||||
|
||||
val internalClassName: String = className.replace('.', '/')
|
||||
|
||||
companion object {
|
||||
fun getClassType(descriptor: ClassifierDescriptor): AndroidClassType {
|
||||
fun getClassTypeInternal(name: String): AndroidClassType? = when (name) {
|
||||
AndroidConst.ACTIVITY_FQNAME -> AndroidClassType.ACTIVITY
|
||||
AndroidConst.FRAGMENT_FQNAME -> AndroidClassType.FRAGMENT
|
||||
AndroidConst.SUPPORT_FRAGMENT_ACTIVITY_FQNAME -> AndroidClassType.SUPPORT_FRAGMENT_ACTIVITY
|
||||
AndroidConst.SUPPORT_FRAGMENT_FQNAME -> AndroidClassType.SUPPORT_FRAGMENT
|
||||
AndroidConst.VIEW_FQNAME -> AndroidClassType.VIEW
|
||||
else -> null
|
||||
}
|
||||
|
||||
if (descriptor is LazyJavaClassDescriptor) {
|
||||
val androidClassType = getClassTypeInternal(DescriptorUtils.getFqName(descriptor).asString())
|
||||
if (androidClassType != null) return androidClassType
|
||||
}
|
||||
else if (descriptor is LazyClassDescriptor) { // For tests (FakeActivity)
|
||||
val androidClassType = getClassTypeInternal(DescriptorUtils.getFqName(descriptor).toString())
|
||||
if (androidClassType != null) return androidClassType
|
||||
}
|
||||
|
||||
for (supertype in descriptor.typeConstructor.supertypes) {
|
||||
val declarationDescriptor = supertype.constructor.declarationDescriptor
|
||||
if (declarationDescriptor != null) {
|
||||
val androidClassType = getClassType(declarationDescriptor)
|
||||
if (androidClassType != AndroidClassType.UNKNOWN) return androidClassType
|
||||
}
|
||||
}
|
||||
|
||||
return AndroidClassType.UNKNOWN
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class AndroidExpressionCodegenExtension : ExpressionCodegenExtension {
|
||||
companion object {
|
||||
private val PROPERTY_NAME = "_\$_findViewCache"
|
||||
private val CACHED_FIND_VIEW_BY_ID_METHOD_NAME = "_\$_findCachedViewById"
|
||||
val CLEAR_CACHE_METHOD_NAME = "_\$_clearFindViewByIdCache"
|
||||
val ON_DESTROY_METHOD_NAME = "onDestroyView"
|
||||
|
||||
fun isCacheSupported(receiverDescriptor: ClassDescriptor, descriptor: PropertyDescriptor? = null): Boolean {
|
||||
val receiverIsKotlinClass = receiverDescriptor.source is KotlinSourceElement
|
||||
return receiverIsKotlinClass && when (descriptor) {
|
||||
is AndroidSyntheticProperty -> !descriptor.alwaysCastToView
|
||||
else -> true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class SyntheticPartsGenerateContext(
|
||||
val classBuilder: ClassBuilder,
|
||||
val state: GenerationState,
|
||||
val descriptor: ClassDescriptor,
|
||||
val classOrObject: KtClassOrObject,
|
||||
val androidClassType: AndroidClassType)
|
||||
|
||||
override fun applyProperty(receiver: StackValue, resolvedCall: ResolvedCall<*>, c: ExpressionCodegenExtension.Context): StackValue? {
|
||||
val resultingDescriptor = resolvedCall.resultingDescriptor
|
||||
return if (resultingDescriptor is PropertyDescriptor) {
|
||||
return generateSyntheticPropertyCall(receiver, resolvedCall, c, resultingDescriptor)
|
||||
}
|
||||
else null
|
||||
}
|
||||
|
||||
override fun applyFunction(receiver: StackValue, resolvedCall: ResolvedCall<*>, c: ExpressionCodegenExtension.Context): StackValue? {
|
||||
val resultingDescriptor = resolvedCall.resultingDescriptor
|
||||
return if (resultingDescriptor is FunctionDescriptor) {
|
||||
return generateSyntheticFunctionCall(receiver, resolvedCall, c, resultingDescriptor)
|
||||
}
|
||||
else null
|
||||
}
|
||||
|
||||
private fun generateSyntheticFunctionCall(
|
||||
receiver: StackValue,
|
||||
resolvedCall: ResolvedCall<*>,
|
||||
c: ExpressionCodegenExtension.Context,
|
||||
functionDescriptor: FunctionDescriptor
|
||||
): StackValue? {
|
||||
if (functionDescriptor !is AndroidSyntheticFunction) return null
|
||||
if (functionDescriptor.name.asString() != AndroidConst.CLEAR_FUNCTION_NAME) return null
|
||||
|
||||
val receiverDescriptor = resolvedCall.getReceiverDeclarationDescriptor() as? ClassDescriptor ?: return null
|
||||
if (!isCacheSupported(receiverDescriptor)) return StackValue.functionCall(Type.VOID_TYPE) {}
|
||||
|
||||
val androidClassType = AndroidClassType.getClassType(receiverDescriptor)
|
||||
if (androidClassType == AndroidClassType.UNKNOWN) return null
|
||||
|
||||
return StackValue.functionCall(Type.VOID_TYPE) {
|
||||
val bytecodeClassName = c.typeMapper.mapType(receiverDescriptor).internalName
|
||||
|
||||
receiver.put(c.typeMapper.mapType(receiverDescriptor), it)
|
||||
it.invokevirtual(bytecodeClassName, CLEAR_CACHE_METHOD_NAME, "()V", false)
|
||||
}
|
||||
}
|
||||
|
||||
private fun generateSyntheticPropertyCall(
|
||||
receiver: StackValue,
|
||||
resolvedCall: ResolvedCall<*>,
|
||||
c: ExpressionCodegenExtension.Context,
|
||||
descriptor: PropertyDescriptor
|
||||
): StackValue? {
|
||||
if (descriptor !is AndroidSyntheticProperty) return null
|
||||
val packageFragment = descriptor.containingDeclaration as? AndroidSyntheticPackageFragmentDescriptor ?: return null
|
||||
val androidPackage = packageFragment.packageData.moduleData.module.applicationPackage
|
||||
val receiverDescriptor = resolvedCall.getReceiverDeclarationDescriptor() as? ClassDescriptor ?: return null
|
||||
val androidClassType = AndroidClassType.getClassType(receiverDescriptor)
|
||||
|
||||
return SyntheticProperty(receiver, c.typeMapper, descriptor, receiverDescriptor, androidClassType, androidPackage)
|
||||
}
|
||||
|
||||
private class SyntheticProperty(
|
||||
val receiver: StackValue,
|
||||
val typeMapper: KotlinTypeMapper,
|
||||
val propertyDescriptor: PropertyDescriptor,
|
||||
val receiverDescriptor: ClassDescriptor,
|
||||
val androidClassType: AndroidClassType,
|
||||
val androidPackage: String
|
||||
) : StackValue(typeMapper.mapType(propertyDescriptor.returnType!!)) {
|
||||
|
||||
override fun putSelector(type: Type, v: InstructionAdapter) {
|
||||
val returnTypeString = typeMapper.mapType(propertyDescriptor.type.lowerIfFlexible()).className
|
||||
if (AndroidConst.FRAGMENT_FQNAME == returnTypeString || AndroidConst.SUPPORT_FRAGMENT_FQNAME == returnTypeString) {
|
||||
return putSelectorForFragment(v)
|
||||
}
|
||||
|
||||
if (androidClassType.supportsCache && isCacheSupported(receiverDescriptor, propertyDescriptor)) {
|
||||
val declarationDescriptorType = typeMapper.mapType(receiverDescriptor)
|
||||
receiver.put(declarationDescriptorType, v)
|
||||
v.getstatic(androidPackage.replace(".", "/") + "/R\$id", propertyDescriptor.name.asString(), "I")
|
||||
v.invokevirtual(declarationDescriptorType.internalName, CACHED_FIND_VIEW_BY_ID_METHOD_NAME, "(I)Landroid/view/View;", false)
|
||||
}
|
||||
else {
|
||||
when (androidClassType) {
|
||||
AndroidClassType.ACTIVITY, AndroidClassType.SUPPORT_FRAGMENT_ACTIVITY, AndroidClassType.VIEW -> {
|
||||
receiver.put(Type.getType("L${androidClassType.internalClassName};"), v)
|
||||
getResourceId(v)
|
||||
v.invokevirtual(androidClassType.internalClassName, "findViewById", "(I)Landroid/view/View;", false)
|
||||
}
|
||||
AndroidClassType.FRAGMENT, AndroidClassType.SUPPORT_FRAGMENT -> {
|
||||
receiver.put(Type.getType("L${androidClassType.internalClassName};"), v)
|
||||
v.invokevirtual(androidClassType.internalClassName, "getView", "()Landroid/view/View;", false)
|
||||
getResourceId(v)
|
||||
v.invokevirtual("android/view/View", "findViewById", "(I)Landroid/view/View;", false)
|
||||
}
|
||||
else -> throw IllegalStateException("Invalid Android class type: $androidClassType") // Should never occur
|
||||
}
|
||||
}
|
||||
|
||||
v.checkcast(this.type)
|
||||
}
|
||||
|
||||
private fun putSelectorForFragment(v: InstructionAdapter) {
|
||||
receiver.put(Type.getType("L${androidClassType.internalClassName};"), v)
|
||||
|
||||
when (androidClassType) {
|
||||
AndroidClassType.ACTIVITY, AndroidClassType.FRAGMENT -> {
|
||||
v.invokevirtual(androidClassType.internalClassName, "getFragmentManager", "()Landroid/app/FragmentManager;", false)
|
||||
getResourceId(v)
|
||||
v.invokevirtual("android/app/FragmentManager", "findFragmentById", "(I)Landroid/app/Fragment;", false)
|
||||
}
|
||||
AndroidClassType.SUPPORT_FRAGMENT -> {
|
||||
v.invokevirtual(androidClassType.internalClassName, "getFragmentManager", "()Landroid/support/v4/app/FragmentManager;", false)
|
||||
getResourceId(v)
|
||||
v.invokevirtual("android/support/v4/app/FragmentManager", "findFragmentById", "(I)Landroid/support/v4/app/Fragment;", false)
|
||||
}
|
||||
AndroidClassType.SUPPORT_FRAGMENT_ACTIVITY -> {
|
||||
v.invokevirtual(androidClassType.internalClassName, "getSupportFragmentManager", "()Landroid/support/v4/app/FragmentManager;", false)
|
||||
getResourceId(v)
|
||||
v.invokevirtual("android/support/v4/app/FragmentManager", "findFragmentById", "(I)Landroid/support/v4/app/Fragment;", false)
|
||||
}
|
||||
else -> throw IllegalStateException("Invalid Android class type: $androidClassType") // Should never occur
|
||||
}
|
||||
|
||||
v.checkcast(this.type)
|
||||
}
|
||||
|
||||
fun getResourceId(v: InstructionAdapter) {
|
||||
v.getstatic(androidPackage.replace(".", "/") + "/R\$id", propertyDescriptor.name.asString(), "I")
|
||||
}
|
||||
}
|
||||
|
||||
private fun ResolvedCall<*>.getReceiverDeclarationDescriptor(): ClassifierDescriptor? {
|
||||
return (extensionReceiver as ReceiverValue).type.constructor.declarationDescriptor
|
||||
}
|
||||
|
||||
override fun generateClassSyntheticParts(
|
||||
classBuilder: ClassBuilder,
|
||||
state: GenerationState,
|
||||
classOrObject: KtClassOrObject,
|
||||
descriptor: ClassDescriptor
|
||||
) {
|
||||
if (descriptor.kind != ClassKind.CLASS || descriptor.isInner || DescriptorUtils.isLocal(descriptor)) return
|
||||
|
||||
// Do not generate anything if class is not supported
|
||||
val androidClassType = AndroidClassType.getClassType(descriptor)
|
||||
if (androidClassType == AndroidClassType.UNKNOWN) return
|
||||
|
||||
val context = SyntheticPartsGenerateContext(classBuilder, state, descriptor, classOrObject, androidClassType)
|
||||
context.generateCachedFindViewByIdFunction()
|
||||
context.generateClearCacheFunction()
|
||||
|
||||
if (androidClassType.fragment) {
|
||||
val classMembers = descriptor.unsubstitutedMemberScope.getContributedDescriptors()
|
||||
val onDestroy = classMembers.firstOrNull { it is FunctionDescriptor && it.isOnDestroyFunction() }
|
||||
if (onDestroy == null) {
|
||||
context.generateOnDestroyFunctionForFragment()
|
||||
}
|
||||
}
|
||||
|
||||
classBuilder.newField(JvmDeclarationOrigin.NO_ORIGIN, ACC_PRIVATE, PROPERTY_NAME, "Ljava/util/HashMap;", null, null)
|
||||
}
|
||||
|
||||
private fun FunctionDescriptor.isOnDestroyFunction(): Boolean {
|
||||
return kind == CallableMemberDescriptor.Kind.DECLARATION
|
||||
&& name.asString() == ON_DESTROY_METHOD_NAME
|
||||
&& (visibility == Visibilities.INHERITED || visibility == Visibilities.PUBLIC)
|
||||
&& (valueParameters.isEmpty())
|
||||
&& (typeParameters.isEmpty())
|
||||
}
|
||||
|
||||
// This generates a simple onDestroy(): Unit = super.onDestroy() function.
|
||||
// CLEAR_CACHE_METHOD_NAME() method call will be inserted in ClassBuilder interceptor.
|
||||
private fun SyntheticPartsGenerateContext.generateOnDestroyFunctionForFragment() {
|
||||
val methodVisitor = classBuilder.newMethod(JvmDeclarationOrigin.NO_ORIGIN, ACC_PUBLIC, ON_DESTROY_METHOD_NAME, "()V", null, null)
|
||||
methodVisitor.visitCode()
|
||||
val iv = InstructionAdapter(methodVisitor)
|
||||
|
||||
val classType = state.typeMapper.mapClass(descriptor)
|
||||
|
||||
iv.load(0, classType)
|
||||
iv.invokespecial(state.typeMapper.mapClass(descriptor.getSuperClassOrAny()).internalName, ON_DESTROY_METHOD_NAME, "()V", false)
|
||||
iv.areturn(Type.VOID_TYPE)
|
||||
|
||||
FunctionCodegen.endVisit(methodVisitor, ON_DESTROY_METHOD_NAME, classOrObject)
|
||||
}
|
||||
|
||||
private fun SyntheticPartsGenerateContext.generateClearCacheFunction() {
|
||||
val methodVisitor = classBuilder.newMethod(JvmDeclarationOrigin.NO_ORIGIN, ACC_PUBLIC, CLEAR_CACHE_METHOD_NAME, "()V", null, null)
|
||||
methodVisitor.visitCode()
|
||||
val iv = InstructionAdapter(methodVisitor)
|
||||
|
||||
val classType = state.typeMapper.mapClass(descriptor)
|
||||
val className = classType.internalName
|
||||
|
||||
fun loadCache() {
|
||||
iv.load(0, classType)
|
||||
iv.getfield(className, PROPERTY_NAME, "Ljava/util/HashMap;")
|
||||
}
|
||||
|
||||
loadCache()
|
||||
val lCacheIsNull = Label()
|
||||
iv.ifnull(lCacheIsNull)
|
||||
|
||||
loadCache()
|
||||
iv.invokevirtual("java/util/HashMap", "clear", "()V", false)
|
||||
|
||||
iv.visitLabel(lCacheIsNull)
|
||||
iv.areturn(Type.VOID_TYPE)
|
||||
FunctionCodegen.endVisit(methodVisitor, CLEAR_CACHE_METHOD_NAME, classOrObject)
|
||||
}
|
||||
|
||||
private fun SyntheticPartsGenerateContext.generateCachedFindViewByIdFunction() {
|
||||
val classType = state.typeMapper.mapClass(descriptor)
|
||||
val className = classType.internalName
|
||||
|
||||
val viewType = Type.getObjectType("android/view/View")
|
||||
|
||||
val methodVisitor = classBuilder.newMethod(
|
||||
JvmDeclarationOrigin.NO_ORIGIN, ACC_PUBLIC, CACHED_FIND_VIEW_BY_ID_METHOD_NAME, "(I)Landroid/view/View;", null, null)
|
||||
methodVisitor.visitCode()
|
||||
val iv = InstructionAdapter(methodVisitor)
|
||||
|
||||
fun loadCache() {
|
||||
iv.load(0, classType)
|
||||
iv.getfield(className, PROPERTY_NAME, "Ljava/util/HashMap;")
|
||||
}
|
||||
|
||||
fun loadId() = iv.load(1, Type.INT_TYPE)
|
||||
|
||||
// Get cache property
|
||||
loadCache()
|
||||
|
||||
val lCacheNonNull = Label()
|
||||
iv.ifnonnull(lCacheNonNull)
|
||||
|
||||
// Init cache if null
|
||||
iv.load(0, classType)
|
||||
iv.anew(Type.getType("Ljava/util/HashMap;"))
|
||||
iv.dup()
|
||||
iv.invokespecial("java/util/HashMap", "<init>", "()V", false)
|
||||
iv.putfield(className, PROPERTY_NAME, "Ljava/util/HashMap;")
|
||||
|
||||
// Get View from cache
|
||||
iv.visitLabel(lCacheNonNull)
|
||||
loadCache()
|
||||
loadId()
|
||||
iv.invokestatic("java/lang/Integer", "valueOf", "(I)Ljava/lang/Integer;", false)
|
||||
iv.invokevirtual("java/util/HashMap", "get", "(Ljava/lang/Object;)Ljava/lang/Object;", false)
|
||||
iv.checkcast(viewType)
|
||||
iv.store(2, viewType)
|
||||
|
||||
val lViewNonNull = Label()
|
||||
iv.load(2, viewType)
|
||||
iv.ifnonnull(lViewNonNull)
|
||||
|
||||
// Resolve View via findViewById if not in cache
|
||||
iv.load(0, classType)
|
||||
when (androidClassType) {
|
||||
AndroidClassType.ACTIVITY, AndroidClassType.SUPPORT_FRAGMENT_ACTIVITY, AndroidClassType.VIEW -> {
|
||||
loadId()
|
||||
iv.invokevirtual(className, "findViewById", "(I)Landroid/view/View;", false)
|
||||
}
|
||||
AndroidClassType.FRAGMENT, AndroidClassType.SUPPORT_FRAGMENT -> {
|
||||
iv.invokevirtual(className, "getView", "()Landroid/view/View;", false)
|
||||
loadId()
|
||||
iv.invokevirtual("android/view/View", "findViewById", "(I)Landroid/view/View;", false)
|
||||
}
|
||||
else -> throw IllegalStateException("Can't generate code for $androidClassType")
|
||||
}
|
||||
iv.store(2, viewType)
|
||||
|
||||
// Store resolved View in cache
|
||||
loadCache()
|
||||
loadId()
|
||||
iv.invokestatic("java/lang/Integer", "valueOf", "(I)Ljava/lang/Integer;", false)
|
||||
iv.load(2, viewType)
|
||||
iv.invokevirtual("java/util/HashMap", "put", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;", false)
|
||||
iv.pop()
|
||||
|
||||
iv.visitLabel(lViewNonNull)
|
||||
iv.load(2, viewType)
|
||||
iv.areturn(viewType)
|
||||
|
||||
FunctionCodegen.endVisit(methodVisitor, CACHED_FIND_VIEW_BY_ID_METHOD_NAME, classOrObject)
|
||||
}
|
||||
}
|
||||
+127
@@ -0,0 +1,127 @@
|
||||
/*
|
||||
* Copyright 2010-2015 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 com.intellij.psi.PsiElement
|
||||
import org.jetbrains.kotlin.codegen.ClassBuilder
|
||||
import org.jetbrains.kotlin.codegen.ClassBuilderFactory
|
||||
import org.jetbrains.kotlin.codegen.DelegatingClassBuilder
|
||||
import org.jetbrains.kotlin.codegen.extensions.ClassBuilderInterceptorExtension
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.diagnostics.DiagnosticSink
|
||||
import org.jetbrains.kotlin.psi.KtClass
|
||||
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
|
||||
|
||||
class AndroidOnDestroyClassBuilderInterceptorExtension : ClassBuilderInterceptorExtension {
|
||||
|
||||
override fun interceptClassBuilderFactory(
|
||||
interceptedFactory: ClassBuilderFactory,
|
||||
bindingContext: BindingContext,
|
||||
diagnostics: DiagnosticSink
|
||||
): ClassBuilderFactory {
|
||||
return AndroidOnDestroyClassBuilderFactory(interceptedFactory, bindingContext)
|
||||
}
|
||||
|
||||
private inner class AndroidOnDestroyClassBuilderFactory(
|
||||
private val delegateFactory: ClassBuilderFactory,
|
||||
val bindingContext: BindingContext
|
||||
) : ClassBuilderFactory {
|
||||
|
||||
override fun newClassBuilder(origin: JvmDeclarationOrigin): ClassBuilder {
|
||||
return AndroidOnDestroyCollectorClassBuilder(delegateFactory.newClassBuilder(origin), bindingContext)
|
||||
}
|
||||
|
||||
override fun getClassBuilderMode() = delegateFactory.classBuilderMode
|
||||
|
||||
override fun asText(builder: ClassBuilder?): String? {
|
||||
return delegateFactory.asText((builder as AndroidOnDestroyCollectorClassBuilder).delegateClassBuilder)
|
||||
}
|
||||
|
||||
override fun asBytes(builder: ClassBuilder?): ByteArray? {
|
||||
return delegateFactory.asBytes((builder as AndroidOnDestroyCollectorClassBuilder).delegateClassBuilder)
|
||||
}
|
||||
|
||||
override fun close() {
|
||||
delegateFactory.close()
|
||||
}
|
||||
}
|
||||
|
||||
private inner class AndroidOnDestroyCollectorClassBuilder(
|
||||
internal val delegateClassBuilder: ClassBuilder,
|
||||
val bindingContext: BindingContext
|
||||
) : DelegatingClassBuilder() {
|
||||
private var currentClass: KtClass? = null
|
||||
private var currentClassName: String? = null
|
||||
|
||||
override fun getDelegate() = delegateClassBuilder
|
||||
|
||||
override fun defineClass(
|
||||
origin: PsiElement?,
|
||||
version: Int,
|
||||
access: Int,
|
||||
name: String,
|
||||
signature: String?,
|
||||
superName: String,
|
||||
interfaces: Array<out String>
|
||||
) {
|
||||
if (origin is KtClass) {
|
||||
currentClass = origin
|
||||
currentClassName = name
|
||||
}
|
||||
super.defineClass(origin, version, access, name, signature, superName, interfaces)
|
||||
}
|
||||
|
||||
override fun newMethod(
|
||||
origin: JvmDeclarationOrigin,
|
||||
access: Int,
|
||||
name: String,
|
||||
desc: String,
|
||||
signature: String?,
|
||||
exceptions: Array<out String>?
|
||||
): MethodVisitor {
|
||||
return object : MethodVisitor(Opcodes.ASM5, super.newMethod(origin, access, name, desc, signature, exceptions)) {
|
||||
override fun visitInsn(opcode: Int) {
|
||||
if (opcode == Opcodes.RETURN) {
|
||||
generateClearCacheMethodCall()
|
||||
}
|
||||
|
||||
super.visitInsn(opcode)
|
||||
}
|
||||
|
||||
private fun generateClearCacheMethodCall() {
|
||||
if (name != AndroidExpressionCodegenExtension.ON_DESTROY_METHOD_NAME || currentClass == null) return
|
||||
if (Type.getArgumentTypes(desc).size != 0) return
|
||||
if (Type.getReturnType(desc) != Type.VOID_TYPE) return
|
||||
|
||||
val classType = currentClassName?.let { Type.getObjectType(it) } ?: return
|
||||
|
||||
val descriptor = bindingContext.get(BindingContext.CLASS, currentClass) as? ClassDescriptor ?: return
|
||||
val androidClassType = AndroidClassType.getClassType(descriptor)
|
||||
if (!androidClassType.fragment) return
|
||||
|
||||
val iv = InstructionAdapter(this)
|
||||
iv.load(0, classType)
|
||||
iv.invokevirtual(currentClassName, AndroidExpressionCodegenExtension.CLEAR_CACHE_METHOD_NAME, "()V", false)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+87
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* Copyright 2010-2015 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.descriptors
|
||||
|
||||
import org.jetbrains.kotlin.android.synthetic.res.*
|
||||
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.impl.PackageFragmentDescriptorImpl
|
||||
import org.jetbrains.kotlin.incremental.components.LookupLocation
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.module
|
||||
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
|
||||
import org.jetbrains.kotlin.resolve.scopes.MemberScope
|
||||
import org.jetbrains.kotlin.resolve.scopes.MemberScopeImpl
|
||||
import org.jetbrains.kotlin.storage.StorageManager
|
||||
import org.jetbrains.kotlin.utils.Printer
|
||||
import java.util.*
|
||||
|
||||
class AndroidSyntheticPackageData(
|
||||
val moduleData: AndroidModuleData,
|
||||
val forView: Boolean,
|
||||
val isDeprecated: Boolean,
|
||||
val resources: List<AndroidResource>)
|
||||
|
||||
class AndroidSyntheticPackageFragmentDescriptor(
|
||||
module: ModuleDescriptor,
|
||||
fqName: FqName,
|
||||
val packageData: AndroidSyntheticPackageData,
|
||||
private val lazyContext: LazySyntheticElementResolveContext,
|
||||
private val storageManager: StorageManager
|
||||
) : PackageFragmentDescriptorImpl(module, fqName) {
|
||||
private val scope = AndroidExtensionPropertiesScope()
|
||||
override fun getMemberScope(): MemberScope = scope
|
||||
|
||||
private inner class AndroidExtensionPropertiesScope : MemberScopeImpl() {
|
||||
private val properties = storageManager.createLazyValue {
|
||||
val packageFragmentDescriptor = this@AndroidSyntheticPackageFragmentDescriptor
|
||||
|
||||
val context = lazyContext()
|
||||
val widgetReceivers = context.getWidgetReceivers(packageData.forView)
|
||||
val fragmentTypes = context.fragmentTypes
|
||||
|
||||
val properties = ArrayList<PropertyDescriptor>(0)
|
||||
for (resource in packageData.resources) {
|
||||
when (resource) {
|
||||
is AndroidResource.Widget -> {
|
||||
val resolvedWidget = resource.resolve(module)
|
||||
for (receiver in widgetReceivers) {
|
||||
properties += genPropertyForWidget(packageFragmentDescriptor, receiver, resolvedWidget, context)
|
||||
}
|
||||
}
|
||||
is AndroidResource.Fragment -> if (!packageData.forView) {
|
||||
for ((receiverType, type) in fragmentTypes) {
|
||||
properties += genPropertyForFragment(packageFragmentDescriptor, receiverType, type, resource, context)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
properties
|
||||
}
|
||||
|
||||
override fun getContributedDescriptors(kindFilter: DescriptorKindFilter, nameFilter: (Name) -> Boolean) =
|
||||
properties().filter { kindFilter.acceptsKinds(DescriptorKindFilter.VARIABLES_MASK) && nameFilter(it.name) }
|
||||
|
||||
override fun getContributedVariables(name: Name, location: LookupLocation) = properties().filter { it.name == name }
|
||||
|
||||
override fun printScopeStructure(p: Printer) {
|
||||
p.println(javaClass.simpleName)
|
||||
}
|
||||
}
|
||||
}
|
||||
+94
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
* Copyright 2010-2015 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.descriptors
|
||||
|
||||
import org.jetbrains.kotlin.android.synthetic.AndroidConst
|
||||
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.module
|
||||
import org.jetbrains.kotlin.serialization.deserialization.findClassAcrossModuleDependencies
|
||||
import org.jetbrains.kotlin.storage.StorageManager
|
||||
import org.jetbrains.kotlin.types.ErrorUtils
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import java.util.*
|
||||
|
||||
class LazySyntheticElementResolveContext(private val module: ModuleDescriptor, private val storageManager: StorageManager) {
|
||||
private val context = storageManager.createLazyValue {
|
||||
module.createResolveContext()
|
||||
}
|
||||
|
||||
internal operator fun invoke() = context()
|
||||
|
||||
private fun ModuleDescriptor.createResolveContext(): SyntheticElementResolveContext {
|
||||
fun find(fqName: String) = module.findClassAcrossModuleDependencies(ClassId.topLevel(FqName(fqName)))
|
||||
|
||||
val viewDescriptor = find(AndroidConst.VIEW_FQNAME) ?: return SyntheticElementResolveContext.ERROR_CONTEXT
|
||||
val activityDescriptor = find(AndroidConst.ACTIVITY_FQNAME) ?: return SyntheticElementResolveContext.ERROR_CONTEXT
|
||||
val fragmentDescriptor = find(AndroidConst.FRAGMENT_FQNAME)
|
||||
val supportActivityDescriptor = find(AndroidConst.SUPPORT_FRAGMENT_ACTIVITY_FQNAME)
|
||||
val supportFragmentDescriptor = find(AndroidConst.SUPPORT_FRAGMENT_FQNAME)
|
||||
|
||||
return SyntheticElementResolveContext(
|
||||
viewDescriptor.defaultType,
|
||||
activityDescriptor.defaultType,
|
||||
fragmentDescriptor?.defaultType,
|
||||
supportActivityDescriptor?.defaultType,
|
||||
supportFragmentDescriptor?.defaultType)
|
||||
}
|
||||
}
|
||||
|
||||
internal class SyntheticElementResolveContext(
|
||||
val viewType: KotlinType,
|
||||
val activityType: KotlinType,
|
||||
val fragmentType: KotlinType?,
|
||||
val supportActivityType: KotlinType?,
|
||||
val supportFragmentType: KotlinType?) {
|
||||
companion object {
|
||||
private fun errorType() = ErrorUtils.createErrorType("")
|
||||
val ERROR_CONTEXT = SyntheticElementResolveContext(errorType(), errorType(), null, null, null)
|
||||
}
|
||||
|
||||
private val widgetReceivers by lazy {
|
||||
val receivers = ArrayList<KotlinType>(3)
|
||||
receivers += activityType
|
||||
fragmentType?.let { receivers += it }
|
||||
supportFragmentType?.let { receivers += it }
|
||||
receivers
|
||||
}
|
||||
|
||||
val fragmentTypes: List<Pair<KotlinType, KotlinType>> by lazy {
|
||||
if (fragmentType == null) {
|
||||
emptyList<Pair<KotlinType, KotlinType>>()
|
||||
}
|
||||
else {
|
||||
val types = ArrayList<Pair<KotlinType, KotlinType>>(4)
|
||||
types += Pair(activityType, fragmentType)
|
||||
types += Pair(fragmentType, fragmentType)
|
||||
if (supportActivityType != null && supportFragmentType != null) {
|
||||
types += Pair(supportFragmentType, supportFragmentType)
|
||||
types += Pair(supportActivityType, supportFragmentType)
|
||||
}
|
||||
types
|
||||
}
|
||||
}
|
||||
|
||||
fun getWidgetReceivers(forView: Boolean): List<KotlinType> {
|
||||
if (forView) return listOf(viewType)
|
||||
return widgetReceivers
|
||||
}
|
||||
}
|
||||
+59
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright 2010-2015 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.descriptors
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.descriptors.impl.PackageFragmentDescriptorImpl
|
||||
import org.jetbrains.kotlin.incremental.components.LookupLocation
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
|
||||
import org.jetbrains.kotlin.resolve.scopes.MemberScopeImpl
|
||||
import org.jetbrains.kotlin.storage.StorageManager
|
||||
import org.jetbrains.kotlin.utils.Printer
|
||||
|
||||
class PredefinedPackageFragmentDescriptor(
|
||||
fqName: String,
|
||||
module: ModuleDescriptor,
|
||||
private val storageManager: StorageManager,
|
||||
val subpackages: List<PackageFragmentDescriptor> = emptyList(),
|
||||
private val descriptors: (PredefinedPackageFragmentDescriptor) -> Collection<DeclarationDescriptor> = { emptyList() }
|
||||
) : PackageFragmentDescriptorImpl(module, FqName(fqName)) {
|
||||
private val calculatedDescriptors = storageManager.createLazyValue {
|
||||
descriptors(this)
|
||||
}
|
||||
|
||||
private val scope = PredefinedScope()
|
||||
override fun getMemberScope() = scope
|
||||
|
||||
inner class PredefinedScope : MemberScopeImpl() {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
override fun getContributedVariables(name: Name, location: LookupLocation) =
|
||||
calculatedDescriptors().filter { it is PropertyDescriptor && it.name == name } as List<PropertyDescriptor>
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
override fun getContributedFunctions(name: Name, location: LookupLocation) =
|
||||
calculatedDescriptors().filter { it is FunctionDescriptor && it.name == name } as List<FunctionDescriptor>
|
||||
|
||||
override fun getContributedDescriptors(kindFilter: DescriptorKindFilter, nameFilter: (Name) -> Boolean) =
|
||||
calculatedDescriptors().filter { nameFilter(it.name) && kindFilter.accepts(it) }
|
||||
|
||||
override fun printScopeStructure(p: Printer) {
|
||||
p.println(javaClass.simpleName)
|
||||
}
|
||||
}
|
||||
}
|
||||
+57
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright 2010-2015 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.diagnostic
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.resolve.calls.checkers.CallChecker
|
||||
import org.jetbrains.kotlin.resolve.calls.context.BasicCallResolutionContext
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
||||
import org.jetbrains.kotlin.android.synthetic.diagnostic.ErrorsAndroid.*
|
||||
import org.jetbrains.kotlin.android.synthetic.descriptors.AndroidSyntheticPackageFragmentDescriptor
|
||||
import org.jetbrains.kotlin.android.synthetic.res.AndroidSyntheticProperty
|
||||
import org.jetbrains.kotlin.diagnostics.DiagnosticSink
|
||||
import org.jetbrains.kotlin.psi.KtExpression
|
||||
|
||||
class AndroidExtensionPropertiesCallChecker : CallChecker {
|
||||
override fun <F : CallableDescriptor> check(resolvedCall: ResolvedCall<F>, context: BasicCallResolutionContext) {
|
||||
val expression = context.call.calleeExpression ?: return
|
||||
|
||||
val propertyDescriptor = resolvedCall.resultingDescriptor as? PropertyDescriptor ?: return
|
||||
val containingPackage = propertyDescriptor.containingDeclaration as? AndroidSyntheticPackageFragmentDescriptor ?: return
|
||||
val androidSyntheticProperty = propertyDescriptor as? AndroidSyntheticProperty ?: return
|
||||
|
||||
with (context.trace) {
|
||||
checkUnresolvedWidgetType(expression, androidSyntheticProperty)
|
||||
checkDeprecated(expression, containingPackage)
|
||||
}
|
||||
}
|
||||
|
||||
private fun DiagnosticSink.checkDeprecated(expression: KtExpression, packageDescriptor: AndroidSyntheticPackageFragmentDescriptor) {
|
||||
if (packageDescriptor.packageData.isDeprecated) {
|
||||
report(SYNTHETIC_DEPRECATED_PACKAGE.on(expression))
|
||||
}
|
||||
}
|
||||
|
||||
private fun DiagnosticSink.checkUnresolvedWidgetType(expression: KtExpression, property: AndroidSyntheticProperty) {
|
||||
if (!property.isErrorType) return
|
||||
val type = property.errorType ?: return
|
||||
|
||||
val warning = if (type.contains('.')) SYNTHETIC_UNRESOLVED_WIDGET_TYPE else SYNTHETIC_INVALID_WIDGET_TYPE
|
||||
report(warning.on(expression, type))
|
||||
}
|
||||
|
||||
}
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright 2010-2015 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.diagnostic
|
||||
|
||||
import org.jetbrains.kotlin.diagnostics.rendering.DefaultErrorMessages
|
||||
import org.jetbrains.kotlin.diagnostics.rendering.DiagnosticFactoryToRendererMap
|
||||
import org.jetbrains.kotlin.diagnostics.rendering.Renderers
|
||||
|
||||
class DefaultErrorMessagesAndroid : DefaultErrorMessages.Extension {
|
||||
|
||||
private companion object {
|
||||
val MAP = DiagnosticFactoryToRendererMap("Android")
|
||||
|
||||
init {
|
||||
MAP.put(ErrorsAndroid.SYNTHETIC_INVALID_WIDGET_TYPE,
|
||||
"Widget has an invalid type ''{0}''. Please specify the fully qualified widget class name in XML",
|
||||
Renderers.TO_STRING)
|
||||
|
||||
MAP.put(ErrorsAndroid.SYNTHETIC_UNRESOLVED_WIDGET_TYPE,
|
||||
"Widget has an unresolved type ''{0}'', and thus it was upcasted to ''android.view.View''",
|
||||
Renderers.TO_STRING)
|
||||
|
||||
MAP.put(ErrorsAndroid.SYNTHETIC_DEPRECATED_PACKAGE,
|
||||
"Use properties from the build variant packages")
|
||||
}
|
||||
}
|
||||
|
||||
override fun getMap() = MAP
|
||||
}
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright 2010-2015 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.diagnostic;
|
||||
|
||||
import org.jetbrains.kotlin.diagnostics.DiagnosticFactory0;
|
||||
import org.jetbrains.kotlin.diagnostics.DiagnosticFactory1;
|
||||
import org.jetbrains.kotlin.diagnostics.Errors;
|
||||
import org.jetbrains.kotlin.psi.KtExpression;
|
||||
|
||||
import static org.jetbrains.kotlin.diagnostics.Severity.WARNING;
|
||||
|
||||
public interface ErrorsAndroid {
|
||||
DiagnosticFactory1<KtExpression, String> SYNTHETIC_INVALID_WIDGET_TYPE = DiagnosticFactory1.create(WARNING);
|
||||
DiagnosticFactory1<KtExpression, String> SYNTHETIC_UNRESOLVED_WIDGET_TYPE = DiagnosticFactory1.create(WARNING);
|
||||
DiagnosticFactory0<KtExpression> SYNTHETIC_DEPRECATED_PACKAGE = DiagnosticFactory0.create(WARNING);
|
||||
|
||||
@SuppressWarnings("UnusedDeclaration")
|
||||
Object _initializer = new Object() {
|
||||
{
|
||||
Errors.Initializer.initializeFactoryNames(ErrorsAndroid.class);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
+134
@@ -0,0 +1,134 @@
|
||||
/*
|
||||
* Copyright 2010-2015 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.res
|
||||
|
||||
import com.intellij.openapi.module.Module
|
||||
import com.intellij.openapi.module.ModuleServiceManager
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
import com.intellij.openapi.vfs.VirtualFileManager
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.PsiFile
|
||||
import com.intellij.psi.PsiManager
|
||||
import org.jetbrains.kotlin.android.synthetic.AndroidConst
|
||||
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
||||
import org.jetbrains.kotlin.psi.KtProperty
|
||||
import java.util.*
|
||||
|
||||
class AndroidVariantData(val variant: AndroidVariant, private val layouts: Map<String, List<PsiFile>>): Map<String, List<PsiFile>> by layouts
|
||||
class AndroidModuleData(val module: AndroidModule, private val variants: List<AndroidVariantData>): Iterable<AndroidVariantData> by variants {
|
||||
companion object {
|
||||
val EMPTY = AndroidModuleData(AndroidModule("android", listOf()), listOf())
|
||||
}
|
||||
}
|
||||
|
||||
abstract class AndroidLayoutXmlFileManager(val project: Project) {
|
||||
|
||||
abstract val androidModule: AndroidModule?
|
||||
|
||||
open fun propertyToXmlAttributes(propertyDescriptor: PropertyDescriptor): List<PsiElement> = listOf()
|
||||
|
||||
open fun getModuleData(): AndroidModuleData {
|
||||
val androidModule = androidModule ?: return AndroidModuleData.EMPTY
|
||||
return AndroidModuleData(androidModule, androidModule.variants.map { getVariantData(it) })
|
||||
}
|
||||
|
||||
fun getVariantData(variant: AndroidVariant): AndroidVariantData {
|
||||
val psiManager = PsiManager.getInstance(project)
|
||||
val fileManager = VirtualFileManager.getInstance()
|
||||
|
||||
fun VirtualFile.getAllChildren(): List<VirtualFile> {
|
||||
val allChildren = arrayListOf<VirtualFile>()
|
||||
val currentChildren = children ?: emptyArray()
|
||||
for (child in currentChildren) {
|
||||
if (child.isDirectory) {
|
||||
allChildren.addAll(child.getAllChildren())
|
||||
}
|
||||
else {
|
||||
allChildren.add(child)
|
||||
}
|
||||
}
|
||||
return allChildren
|
||||
}
|
||||
|
||||
val resDirectories = variant.resDirectories.map { fileManager.findFileByUrl("file://$it") }
|
||||
val allChildren = resDirectories.flatMap { it?.getAllChildren() ?: listOf() }
|
||||
|
||||
val allLayoutFiles = allChildren.filter { it.parent.name.startsWith("layout") && it.name.toLowerCase().endsWith(".xml") }
|
||||
val allLayoutPsiFiles = allLayoutFiles.fold(ArrayList<PsiFile>(allLayoutFiles.size)) { list, file ->
|
||||
val psiFile = psiManager.findFile(file)
|
||||
if (psiFile != null && psiFile.parent != null) {
|
||||
list += psiFile
|
||||
}
|
||||
list
|
||||
}
|
||||
|
||||
val layoutNameToXmlFiles = allLayoutPsiFiles
|
||||
.groupBy { it.name.substringBeforeLast('.') }
|
||||
.mapValues { it.value.sortedBy { it.parent!!.name.length } }
|
||||
|
||||
return AndroidVariantData(variant, layoutNameToXmlFiles)
|
||||
}
|
||||
|
||||
fun extractResources(files: List<PsiFile>, module: ModuleDescriptor): List<AndroidResource> {
|
||||
return filterDuplicates(doExtractResources(files, module))
|
||||
}
|
||||
|
||||
protected abstract fun doExtractResources(files: List<PsiFile>, module: ModuleDescriptor): List<AndroidResource>
|
||||
|
||||
protected fun parseAndroidResource(id: String, tag: String, sourceElement: PsiElement?): AndroidResource {
|
||||
return when (tag) {
|
||||
"fragment" -> AndroidResource.Fragment(id, sourceElement)
|
||||
"include" -> AndroidResource.Widget(id, AndroidConst.VIEW_FQNAME, sourceElement)
|
||||
else -> AndroidResource.Widget(id, tag, sourceElement)
|
||||
}
|
||||
}
|
||||
|
||||
private fun filterDuplicates(resources: List<AndroidResource>): List<AndroidResource> {
|
||||
val resourceMap = linkedMapOf<String, AndroidResource>()
|
||||
val resourcesToExclude = hashSetOf<String>()
|
||||
|
||||
for (res in resources) {
|
||||
if (resourceMap.contains(res.id)) {
|
||||
val existing = resourceMap[res.id]!!
|
||||
|
||||
if (!res.sameClass(existing)) {
|
||||
resourcesToExclude.add(res.id)
|
||||
}
|
||||
else if (res is AndroidResource.Widget && existing is AndroidResource.Widget) {
|
||||
// Widgets with the same id but different types exist.
|
||||
if (res.xmlType != existing.xmlType && existing.xmlType != AndroidConst.VIEW_FQNAME) {
|
||||
resourceMap.put(res.id, AndroidResource.Widget(res.id, AndroidConst.VIEW_FQNAME, res.sourceElement))
|
||||
}
|
||||
}
|
||||
}
|
||||
else resourceMap.put(res.id, res)
|
||||
}
|
||||
resourcesToExclude.forEach { resourceMap.remove(it) }
|
||||
return resourceMap.values.toList()
|
||||
}
|
||||
|
||||
|
||||
companion object {
|
||||
fun getInstance(module: Module): AndroidLayoutXmlFileManager? {
|
||||
val service = ModuleServiceManager.getService(module, AndroidLayoutXmlFileManager::class.java)
|
||||
return service ?: module.getComponent(AndroidLayoutXmlFileManager::class.java)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+102
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* Copyright 2010-2015 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.res
|
||||
|
||||
import com.intellij.openapi.project.Project
|
||||
import org.jetbrains.kotlin.analyzer.ModuleInfo
|
||||
import org.jetbrains.kotlin.android.synthetic.AndroidConst
|
||||
import org.jetbrains.kotlin.android.synthetic.descriptors.*
|
||||
import org.jetbrains.kotlin.android.synthetic.forEachUntilLast
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.resolve.BindingTrace
|
||||
import org.jetbrains.kotlin.resolve.jvm.extensions.PackageFragmentProviderExtension
|
||||
import org.jetbrains.kotlin.storage.StorageManager
|
||||
|
||||
abstract class AndroidPackageFragmentProviderExtension : PackageFragmentProviderExtension {
|
||||
protected abstract fun getLayoutXmlFileManager(project: Project, moduleInfo: ModuleInfo?): AndroidLayoutXmlFileManager?
|
||||
|
||||
override fun getPackageFragmentProvider(
|
||||
project: Project,
|
||||
module: ModuleDescriptor,
|
||||
storageManager: StorageManager,
|
||||
trace: BindingTrace,
|
||||
moduleInfo: ModuleInfo?
|
||||
): PackageFragmentProvider? {
|
||||
val layoutXmlFileManager = getLayoutXmlFileManager(project, moduleInfo) ?: return null
|
||||
|
||||
val moduleData = layoutXmlFileManager.getModuleData()
|
||||
|
||||
val lazyContext = LazySyntheticElementResolveContext(module, storageManager)
|
||||
|
||||
val allPackageDescriptors = arrayListOf<PackageFragmentDescriptor>()
|
||||
val packagesToLookupInCompletion = arrayListOf<PackageFragmentDescriptor>()
|
||||
|
||||
// Packages with synthetic properties
|
||||
for (variantData in moduleData) {
|
||||
for ((layoutName, layouts) in variantData) {
|
||||
fun createPackageFragment(fqName: String, forView: Boolean, isDeprecated: Boolean = false) {
|
||||
val resources = layoutXmlFileManager.extractResources(layouts, module)
|
||||
val packageData = AndroidSyntheticPackageData(moduleData, forView, isDeprecated, resources)
|
||||
val packageDescriptor = AndroidSyntheticPackageFragmentDescriptor(
|
||||
module, FqName(fqName), packageData, lazyContext, storageManager)
|
||||
packagesToLookupInCompletion += packageDescriptor
|
||||
allPackageDescriptors += packageDescriptor
|
||||
}
|
||||
|
||||
val packageFqName = AndroidConst.SYNTHETIC_PACKAGE + '.' + variantData.variant.name + '.' + layoutName
|
||||
|
||||
createPackageFragment(packageFqName, false)
|
||||
createPackageFragment(packageFqName + ".view", true)
|
||||
}
|
||||
}
|
||||
|
||||
// Empty middle packages
|
||||
AndroidConst.SYNTHETIC_SUBPACKAGES.forEachUntilLast { s ->
|
||||
allPackageDescriptors += PredefinedPackageFragmentDescriptor(s, module, storageManager)
|
||||
}
|
||||
|
||||
for (variantData in moduleData) {
|
||||
val fqName = AndroidConst.SYNTHETIC_PACKAGE + '.' + variantData.variant.name
|
||||
allPackageDescriptors += PredefinedPackageFragmentDescriptor(fqName, module, storageManager)
|
||||
}
|
||||
|
||||
// Package with clearFindViewByIdCache()
|
||||
AndroidConst.SYNTHETIC_SUBPACKAGES.last().let { s ->
|
||||
val packageDescriptor = PredefinedPackageFragmentDescriptor(s, module, storageManager, packagesToLookupInCompletion) { descriptor ->
|
||||
lazyContext().getWidgetReceivers(false).map { genClearCacheFunction(descriptor, it) }
|
||||
}
|
||||
packagesToLookupInCompletion += packageDescriptor
|
||||
allPackageDescriptors += packageDescriptor
|
||||
}
|
||||
|
||||
return AndroidSyntheticPackageFragmentProvider(allPackageDescriptors)
|
||||
}
|
||||
}
|
||||
|
||||
class AndroidSyntheticPackageFragmentProvider(
|
||||
val packageFragments: Collection<PackageFragmentDescriptor>
|
||||
) : PackageFragmentProvider {
|
||||
override fun getPackageFragments(fqName: FqName) = packageFragments.filter { it.fqName == fqName }
|
||||
|
||||
override fun getSubPackagesOf(fqName: FqName, nameFilter: (Name) -> Boolean) =
|
||||
packageFragments.asSequence()
|
||||
.map { it.fqName }
|
||||
.filter { !it.isRoot && it.parent() == fqName }
|
||||
.toList()
|
||||
}
|
||||
+66
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Copyright 2010-2015 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.res
|
||||
|
||||
import com.intellij.openapi.diagnostic.Logger
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.psi.PsiFile
|
||||
import org.jetbrains.kotlin.android.synthetic.AndroidXmlHandler
|
||||
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
||||
import java.io.ByteArrayInputStream
|
||||
import javax.xml.parsers.SAXParser
|
||||
import javax.xml.parsers.SAXParserFactory
|
||||
|
||||
class CliAndroidLayoutXmlFileManager(
|
||||
project: Project,
|
||||
private val applicationPackage: String,
|
||||
private val variants: List<AndroidVariant>
|
||||
) : AndroidLayoutXmlFileManager(project) {
|
||||
private companion object {
|
||||
val LOG = Logger.getInstance(CliAndroidLayoutXmlFileManager::class.java)
|
||||
}
|
||||
|
||||
override val androidModule = AndroidModule(applicationPackage, variants)
|
||||
|
||||
private val saxParser: SAXParser = initSAX()
|
||||
|
||||
override fun doExtractResources(files: List<PsiFile>, module: ModuleDescriptor): List<AndroidResource> {
|
||||
val resources = arrayListOf<AndroidResource>()
|
||||
|
||||
val handler = AndroidXmlHandler { id, tag ->
|
||||
resources += parseAndroidResource(id, tag, null)
|
||||
}
|
||||
|
||||
for (file in files) {
|
||||
try {
|
||||
val inputStream = ByteArrayInputStream(file.virtualFile.contentsToByteArray())
|
||||
saxParser.parse(inputStream, handler)
|
||||
} catch (e: Throwable) {
|
||||
LOG.error(e)
|
||||
}
|
||||
}
|
||||
|
||||
return resources
|
||||
}
|
||||
|
||||
protected fun initSAX(): SAXParser {
|
||||
val saxFactory = SAXParserFactory.newInstance()
|
||||
saxFactory.isNamespaceAware = true
|
||||
return saxFactory.newSAXParser()
|
||||
}
|
||||
|
||||
}
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright 2010-2015 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.res
|
||||
|
||||
import com.intellij.openapi.components.ServiceManager
|
||||
import com.intellij.openapi.project.Project
|
||||
import org.jetbrains.kotlin.analyzer.ModuleInfo
|
||||
|
||||
class CliAndroidPackageFragmentProviderExtension : AndroidPackageFragmentProviderExtension() {
|
||||
override fun getLayoutXmlFileManager(project: Project, moduleInfo: ModuleInfo?): AndroidLayoutXmlFileManager? {
|
||||
return ServiceManager.getService(project, AndroidLayoutXmlFileManager::class.java)
|
||||
}
|
||||
}
|
||||
+89
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* Copyright 2010-2015 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.res
|
||||
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.util.CachedValue
|
||||
import com.intellij.psi.util.CachedValueProvider
|
||||
import com.intellij.psi.util.CachedValuesManager
|
||||
import org.jetbrains.kotlin.android.synthetic.AndroidConst
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.serialization.deserialization.findClassAcrossModuleDependencies
|
||||
|
||||
class AndroidVariant(val name: String, val resDirectories: List<String>) {
|
||||
val packageName: String = name
|
||||
val isMainVariant: Boolean
|
||||
get() = name == "main"
|
||||
|
||||
companion object {
|
||||
fun createMainVariant(resDirectories: List<String>) = AndroidVariant("main", resDirectories)
|
||||
}
|
||||
}
|
||||
|
||||
class AndroidModule(val applicationPackage: String, val variants: List<AndroidVariant>) {
|
||||
override fun equals(other: Any?) = other is AndroidModule && applicationPackage == other.applicationPackage
|
||||
override fun hashCode() = applicationPackage.hashCode()
|
||||
}
|
||||
|
||||
sealed class AndroidResource(val id: String, val sourceElement: PsiElement?) {
|
||||
open fun sameClass(other: AndroidResource): Boolean = false
|
||||
|
||||
class Widget(
|
||||
id: String,
|
||||
val xmlType: String,
|
||||
sourceElement: PsiElement?
|
||||
) : AndroidResource(id, sourceElement) {
|
||||
override fun sameClass(other: AndroidResource) = other is Widget
|
||||
}
|
||||
|
||||
class Fragment(id: String, sourceElement: PsiElement?) : AndroidResource(id, sourceElement) {
|
||||
override fun sameClass(other: AndroidResource) = other is Fragment
|
||||
}
|
||||
}
|
||||
|
||||
fun <T> cachedValue(project: Project, result: () -> CachedValueProvider.Result<T>): CachedValue<T> {
|
||||
return CachedValuesManager.getManager(project).createCachedValue(result, false)
|
||||
}
|
||||
|
||||
class ResolvedWidget(val widget: AndroidResource.Widget, val viewClassDescriptor: ClassDescriptor?) {
|
||||
val isErrorType: Boolean
|
||||
get() = viewClassDescriptor == null
|
||||
|
||||
val errorType: String?
|
||||
get() = if (isErrorType) widget.xmlType else null
|
||||
}
|
||||
|
||||
fun AndroidResource.Widget.resolve(module: ModuleDescriptor): ResolvedWidget {
|
||||
fun resolve(fqName: String) = module.findClassAcrossModuleDependencies(ClassId.topLevel(FqName(fqName)))
|
||||
|
||||
if ('.' in xmlType) {
|
||||
return ResolvedWidget(this, resolve(xmlType))
|
||||
}
|
||||
|
||||
for (packageName in AndroidConst.FQNAME_RESOLVE_PACKAGES) {
|
||||
val classDescriptor = resolve("$packageName.$xmlType")
|
||||
if (classDescriptor != null) {
|
||||
return ResolvedWidget(this, classDescriptor)
|
||||
}
|
||||
}
|
||||
|
||||
return ResolvedWidget(this, null)
|
||||
}
|
||||
+145
@@ -0,0 +1,145 @@
|
||||
/*
|
||||
* Copyright 2010-2015 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.res
|
||||
|
||||
import com.intellij.psi.PsiElement
|
||||
import org.jetbrains.kotlin.android.synthetic.AndroidConst
|
||||
import org.jetbrains.kotlin.android.synthetic.descriptors.AndroidSyntheticPackageFragmentDescriptor
|
||||
import org.jetbrains.kotlin.android.synthetic.descriptors.SyntheticElementResolveContext
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
||||
import org.jetbrains.kotlin.descriptors.impl.PropertyDescriptorImpl
|
||||
import org.jetbrains.kotlin.descriptors.impl.PropertyGetterDescriptorImpl
|
||||
import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameUnsafe
|
||||
import org.jetbrains.kotlin.resolve.source.PsiSourceElement
|
||||
import org.jetbrains.kotlin.types.*
|
||||
import org.jetbrains.kotlin.types.typeUtil.makeNullable
|
||||
|
||||
private class XmlSourceElement(override val psi: PsiElement) : PsiSourceElement
|
||||
|
||||
internal fun genClearCacheFunction(packageFragmentDescriptor: PackageFragmentDescriptor, receiverType: KotlinType): FunctionDescriptor {
|
||||
val function = object : AndroidSyntheticFunction, SimpleFunctionDescriptorImpl(
|
||||
packageFragmentDescriptor,
|
||||
null,
|
||||
Annotations.EMPTY,
|
||||
Name.identifier(AndroidConst.CLEAR_FUNCTION_NAME),
|
||||
CallableMemberDescriptor.Kind.SYNTHESIZED,
|
||||
SourceElement.NO_SOURCE) {}
|
||||
|
||||
val unitType = packageFragmentDescriptor.builtIns.unitType
|
||||
function.initialize(receiverType, null, emptyList(), emptyList(), unitType, Modality.FINAL, Visibilities.PUBLIC)
|
||||
return function
|
||||
}
|
||||
|
||||
internal fun genPropertyForWidget(
|
||||
packageFragmentDescriptor: AndroidSyntheticPackageFragmentDescriptor,
|
||||
receiverType: KotlinType,
|
||||
resolvedWidget: ResolvedWidget,
|
||||
context: SyntheticElementResolveContext
|
||||
): PropertyDescriptor {
|
||||
val sourceEl = resolvedWidget.widget.sourceElement?.let { XmlSourceElement(it) } ?: SourceElement.NO_SOURCE
|
||||
|
||||
val classDescriptor = resolvedWidget.viewClassDescriptor
|
||||
val type = classDescriptor?.let {
|
||||
val defaultType = classDescriptor.defaultType
|
||||
if (defaultType.constructor.parameters.isEmpty())
|
||||
defaultType
|
||||
else
|
||||
KotlinTypeImpl.create(Annotations.EMPTY, classDescriptor, false,
|
||||
defaultType.constructor.parameters.map { StarProjectionImpl(it) })
|
||||
} ?: context.viewType
|
||||
|
||||
return genProperty(resolvedWidget.widget.id, receiverType, type, packageFragmentDescriptor, sourceEl, context, resolvedWidget.errorType)
|
||||
}
|
||||
|
||||
internal fun genPropertyForFragment(
|
||||
packageFragmentDescriptor: PackageFragmentDescriptor,
|
||||
receiverType: KotlinType,
|
||||
type: KotlinType,
|
||||
fragment: AndroidResource.Fragment,
|
||||
context: SyntheticElementResolveContext
|
||||
): PropertyDescriptor {
|
||||
val sourceElement = fragment.sourceElement?.let { XmlSourceElement(it) } ?: SourceElement.NO_SOURCE
|
||||
return genProperty(fragment.id, receiverType, type, packageFragmentDescriptor, sourceElement, context, null)
|
||||
}
|
||||
|
||||
private fun genProperty(
|
||||
id: String,
|
||||
receiverType: KotlinType,
|
||||
type: KotlinType,
|
||||
containingDeclaration: DeclarationDescriptor,
|
||||
sourceElement: SourceElement,
|
||||
context: SyntheticElementResolveContext,
|
||||
errorType: String?
|
||||
): PropertyDescriptor {
|
||||
val alwaysCastToView = type.constructor.declarationDescriptor?.fqNameUnsafe?.asString() == AndroidConst.VIEWSTUB_FQNAME
|
||||
|
||||
val property = object : AndroidSyntheticProperty, PropertyDescriptorImpl(
|
||||
containingDeclaration,
|
||||
null,
|
||||
Annotations.EMPTY,
|
||||
Modality.FINAL,
|
||||
Visibilities.PUBLIC,
|
||||
false,
|
||||
Name.identifier(id),
|
||||
CallableMemberDescriptor.Kind.SYNTHESIZED,
|
||||
sourceElement,
|
||||
false,
|
||||
false) {
|
||||
override val errorType = errorType
|
||||
override val alwaysCastToView = alwaysCastToView
|
||||
}
|
||||
|
||||
val actualType = if (alwaysCastToView) context.viewType else type
|
||||
val flexibleType = DelegatingFlexibleType.create(actualType, actualType.makeNullable(), FlexibleTypeCapabilities.NONE)
|
||||
property.setType(
|
||||
flexibleType,
|
||||
emptyList<TypeParameterDescriptor>(),
|
||||
null,
|
||||
receiverType)
|
||||
|
||||
val getter = PropertyGetterDescriptorImpl(
|
||||
property,
|
||||
Annotations.EMPTY,
|
||||
Modality.FINAL,
|
||||
Visibilities.PUBLIC,
|
||||
false,
|
||||
false,
|
||||
CallableMemberDescriptor.Kind.SYNTHESIZED,
|
||||
null,
|
||||
SourceElement.NO_SOURCE
|
||||
)
|
||||
|
||||
getter.initialize(null)
|
||||
|
||||
property.initialize(getter, null)
|
||||
|
||||
return property
|
||||
}
|
||||
|
||||
interface AndroidSyntheticFunction
|
||||
|
||||
interface AndroidSyntheticProperty {
|
||||
val errorType: String?
|
||||
val alwaysCastToView: Boolean
|
||||
|
||||
val isErrorType: Boolean
|
||||
get() = errorType != null
|
||||
}
|
||||
Vendored
+8
@@ -0,0 +1,8 @@
|
||||
package android.app
|
||||
|
||||
import android.view.View
|
||||
import android.content.Context
|
||||
|
||||
open class Activity: Context {
|
||||
open fun findViewById(id: Int): View? = null
|
||||
}
|
||||
+1
@@ -0,0 +1 @@
|
||||
package android.appwidget
|
||||
Vendored
+3
@@ -0,0 +1,3 @@
|
||||
package android.content
|
||||
|
||||
interface Context
|
||||
Vendored
+9
@@ -0,0 +1,9 @@
|
||||
package android.app
|
||||
|
||||
import android.view.View
|
||||
import android.app.Activity
|
||||
|
||||
abstract class Fragment {
|
||||
open fun getActivity(): Activity = throw Exception("Function getActivity() is not overridden")
|
||||
open fun getView(): View = throw Exception("Function getView() is not overridden")
|
||||
}
|
||||
+1
@@ -0,0 +1 @@
|
||||
package android.inputmethodservice
|
||||
plugins/android-extensions/android-extensions-compiler/testData/codegen/android/FakeOpenglPackage.kt
Vendored
+1
@@ -0,0 +1 @@
|
||||
package android.opengl
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
package android.support.v4.app
|
||||
|
||||
import android.view.View
|
||||
import android.app.Activity
|
||||
|
||||
abstract class Fragment {
|
||||
open fun getActivity(): Activity = throw Exception("Function getActivity() is not overridden")
|
||||
open fun getView(): View = throw Exception("Function getView() is not overridden")
|
||||
}
|
||||
Vendored
+7
@@ -0,0 +1,7 @@
|
||||
package android.view
|
||||
|
||||
import android.content.Context
|
||||
|
||||
open class View(ctx: Context) {
|
||||
open fun findViewById(id: Int): View? = null
|
||||
}
|
||||
plugins/android-extensions/android-extensions-compiler/testData/codegen/android/FakeWebkitPackage.kt
Vendored
+1
@@ -0,0 +1 @@
|
||||
package android.webkit
|
||||
Vendored
+11
@@ -0,0 +1,11 @@
|
||||
package android.widget
|
||||
|
||||
import android.view.View
|
||||
import android.content.Context
|
||||
|
||||
open class Button(ctx: Context): View(ctx) {override fun toString() = "Button"}
|
||||
open class EditText(ctx: Context): View(ctx) {override fun toString() = "EditText"}
|
||||
open class TextView(ctx: Context): View(ctx) {override fun toString() = "TextView"}
|
||||
open class FrameLayout(ctx: Context): View(ctx) {override fun toString() = "FrameLayout"}
|
||||
open class RelativeLayout(ctx: Context): View(ctx) {override fun toString() = "RelativeLayout"}
|
||||
open class ImageView(ctx: Context): View(ctx) {override fun toString() = "ImageView"}
|
||||
Vendored
+34
@@ -0,0 +1,34 @@
|
||||
package test
|
||||
|
||||
import android.app.Activity
|
||||
import android.view.View
|
||||
import android.widget.*
|
||||
import org.my.cool.MyButton
|
||||
import kotlinx.android.synthetic.main.layout.*
|
||||
|
||||
class R {
|
||||
class id {
|
||||
companion object {
|
||||
const val login = 5
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class MyActivity(): Activity() {
|
||||
val buttonWidget = MyButton(this)
|
||||
|
||||
override fun findViewById(id: Int): View? {
|
||||
return when (id) {
|
||||
R.id.login -> buttonWidget
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
public fun box(): String {
|
||||
return if (login.toString() == "MyButton") "OK" else ""
|
||||
}
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
return MyActivity().box()
|
||||
}
|
||||
Vendored
+30
@@ -0,0 +1,30 @@
|
||||
package test
|
||||
|
||||
import android.app.Activity
|
||||
import android.view.View
|
||||
import android.widget.*
|
||||
import org.my.cool.MyButton
|
||||
import kotlinx.android.synthetic.main.layout.*
|
||||
|
||||
class R {
|
||||
class id {
|
||||
companion object {
|
||||
const val login = 5
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class MyActivity(): Activity() {
|
||||
val buttonWidget = MyButton(this)
|
||||
|
||||
override fun findViewById(id: Int): View? {
|
||||
return when (id) {
|
||||
R.id.login -> buttonWidget
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
return "OK"
|
||||
}
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="test"
|
||||
android:versionCode="1"
|
||||
android:versionName="1.0" >
|
||||
|
||||
<uses-permission android:name="android.permission.READ_CONTACTS"/>
|
||||
<uses-sdk
|
||||
android:minSdkVersion="18"
|
||||
android:targetSdkVersion="18" />
|
||||
<permission android:name="android"></permission>
|
||||
|
||||
<application
|
||||
android:allowBackup="true"
|
||||
android:icon="@drawable/ic_launcher"
|
||||
android:label="@string/app_name"
|
||||
android:theme="@style/Theme.Sample" >
|
||||
<activity
|
||||
android:name="com.example.android.basiccontactables.MainActivity"
|
||||
android:label="@string/app_name"
|
||||
android:launchMode="singleTop">
|
||||
<meta-data
|
||||
android:name="android.app.searchable"
|
||||
android:resource="@xml/searchable" />
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.SEARCH" />
|
||||
</intent-filter>
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
</application>
|
||||
</manifest>
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
package org.my.cool
|
||||
|
||||
import android.widget.Button
|
||||
import android.app.Activity
|
||||
|
||||
class MyButton(ctx: Activity): Button(ctx) {
|
||||
override fun toString(): String {return "MyButton"}
|
||||
}
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:context=".ItemDetailActivity"
|
||||
tools:ignore="MergeRootFrame" >
|
||||
|
||||
<view
|
||||
class="org.my.cool.MyButton"
|
||||
android:id="@+id/login"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Sign in" />
|
||||
|
||||
</FrameLayout>
|
||||
Vendored
+34
@@ -0,0 +1,34 @@
|
||||
package test
|
||||
|
||||
import android.app.Activity
|
||||
import android.view.View
|
||||
import android.widget.*
|
||||
import org.my.cool.MyButton
|
||||
import kotlinx.android.synthetic.main.layout.*
|
||||
|
||||
class R {
|
||||
class id {
|
||||
companion object {
|
||||
const val login = 5
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class MyActivity(): Activity() {
|
||||
val buttonWidget = MyButton(this)
|
||||
|
||||
override fun findViewById(id: Int): View? {
|
||||
return when (id) {
|
||||
R.id.login -> buttonWidget
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
public fun box(): String {
|
||||
return if (login.toString() == "MyButton") "OK" else ""
|
||||
}
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
return MyActivity().box()
|
||||
}
|
||||
Vendored
+30
@@ -0,0 +1,30 @@
|
||||
package test
|
||||
|
||||
import android.app.Activity
|
||||
import android.view.View
|
||||
import android.widget.*
|
||||
import org.my.cool.MyButton
|
||||
import kotlinx.android.synthetic.main.layout.*
|
||||
|
||||
class R {
|
||||
class id {
|
||||
companion object {
|
||||
const val login = 5
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class MyActivity(): Activity() {
|
||||
val buttonWidget = MyButton(this)
|
||||
|
||||
override fun findViewById(id: Int): View? {
|
||||
return when (id) {
|
||||
R.id.login -> buttonWidget
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
return "OK"
|
||||
}
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="test"
|
||||
android:versionCode="1"
|
||||
android:versionName="1.0" >
|
||||
|
||||
<uses-permission android:name="android.permission.READ_CONTACTS"/>
|
||||
<uses-sdk
|
||||
android:minSdkVersion="18"
|
||||
android:targetSdkVersion="18" />
|
||||
<permission android:name="android"></permission>
|
||||
|
||||
<application
|
||||
android:allowBackup="true"
|
||||
android:icon="@drawable/ic_launcher"
|
||||
android:label="@string/app_name"
|
||||
android:theme="@style/Theme.Sample" >
|
||||
<activity
|
||||
android:name="com.example.android.basiccontactables.MainActivity"
|
||||
android:label="@string/app_name"
|
||||
android:launchMode="singleTop">
|
||||
<meta-data
|
||||
android:name="android.app.searchable"
|
||||
android:resource="@xml/searchable" />
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.SEARCH" />
|
||||
</intent-filter>
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
</application>
|
||||
</manifest>
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
package org.my.cool
|
||||
|
||||
import android.widget.Button
|
||||
import android.content.Context
|
||||
|
||||
class MyButton(ctx: Context): Button(ctx) {
|
||||
override fun toString(): String {return "MyButton"}
|
||||
}
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:context=".ItemDetailActivity"
|
||||
tools:ignore="MergeRootFrame" >
|
||||
|
||||
<org.my.cool.MyButton
|
||||
android:id="@+id/login"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Sign in" />
|
||||
|
||||
</FrameLayout>
|
||||
Vendored
+45
@@ -0,0 +1,45 @@
|
||||
package test
|
||||
|
||||
import android.app.Activity
|
||||
import android.app.Fragment
|
||||
import android.content.Context
|
||||
import android.view.View
|
||||
import android.widget.*
|
||||
import org.my.cool.MyButton
|
||||
import kotlinx.android.synthetic.main.layout.*
|
||||
|
||||
class R {
|
||||
class id {
|
||||
companion object {
|
||||
const val login = 5
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class BaseView(ctx: Context) : View(ctx) {
|
||||
val buttonWidget = MyButton(ctx)
|
||||
|
||||
override fun findViewById(id: Int): View? {
|
||||
return when (id) {
|
||||
R.id.login -> buttonWidget
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class MyFragment(): Fragment() {
|
||||
val baseActivity = Activity()
|
||||
val baseView = BaseView(baseActivity)
|
||||
|
||||
override fun getActivity(): Activity = baseActivity
|
||||
|
||||
override fun getView(): View = baseView
|
||||
|
||||
public fun box(): String {
|
||||
return if (login.toString() == "MyButton") "OK" else ""
|
||||
}
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
return MyFragment().box()
|
||||
}
|
||||
Vendored
+32
@@ -0,0 +1,32 @@
|
||||
package test
|
||||
|
||||
import android.app.Activity
|
||||
import android.app.Fragment
|
||||
import android.content.Context
|
||||
import android.view.View
|
||||
import android.widget.*
|
||||
import org.my.cool.MyButton
|
||||
import kotlinx.android.synthetic.main.layout.*
|
||||
|
||||
class R {
|
||||
class id {
|
||||
companion object {
|
||||
const val login = 5
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class BaseView(ctx: Context) : View(ctx) {
|
||||
val buttonWidget = MyButton(ctx)
|
||||
}
|
||||
|
||||
class MyFragment(): Fragment() {
|
||||
val baseActivity = Activity()
|
||||
val baseView = BaseView(baseActivity)
|
||||
|
||||
override fun getView(): View = baseView
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
return "OK"
|
||||
}
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="test"
|
||||
android:versionCode="1"
|
||||
android:versionName="1.0" >
|
||||
|
||||
<uses-permission android:name="android.permission.READ_CONTACTS"/>
|
||||
<uses-sdk
|
||||
android:minSdkVersion="18"
|
||||
android:targetSdkVersion="18" />
|
||||
<permission android:name="android"></permission>
|
||||
|
||||
<application
|
||||
android:allowBackup="true"
|
||||
android:icon="@drawable/ic_launcher"
|
||||
android:label="@string/app_name"
|
||||
android:theme="@style/Theme.Sample" >
|
||||
<activity
|
||||
android:name="com.example.android.basiccontactables.MainActivity"
|
||||
android:label="@string/app_name"
|
||||
android:launchMode="singleTop">
|
||||
<meta-data
|
||||
android:name="android.app.searchable"
|
||||
android:resource="@xml/searchable" />
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.SEARCH" />
|
||||
</intent-filter>
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
</application>
|
||||
</manifest>
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
package org.my.cool
|
||||
|
||||
import android.widget.Button
|
||||
import android.content.Context
|
||||
|
||||
class MyButton(ctx: Context): Button(ctx) {
|
||||
override fun toString(): String {return "MyButton"}
|
||||
}
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:context=".ItemDetailActivity"
|
||||
tools:ignore="MergeRootFrame" >
|
||||
|
||||
<view
|
||||
class="org.my.cool.MyButton"
|
||||
android:id="@+id/login"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Sign in" />
|
||||
|
||||
</FrameLayout>
|
||||
Vendored
+1
@@ -0,0 +1 @@
|
||||
fun box() = "OK"
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="test"
|
||||
android:versionCode="1"
|
||||
android:versionName="1.0" >
|
||||
|
||||
<uses-permission android:name="android.permission.READ_CONTACTS"/>
|
||||
<uses-sdk
|
||||
android:minSdkVersion="18"
|
||||
android:targetSdkVersion="18" />
|
||||
<permission android:name="android"></permission>
|
||||
|
||||
<application
|
||||
android:allowBackup="true"
|
||||
android:icon="@drawable/ic_launcher"
|
||||
android:label="@string/app_name"
|
||||
android:theme="@style/Theme.Sample" >
|
||||
<activity
|
||||
android:name="com.example.android.basiccontactables.MainActivity"
|
||||
android:label="@string/app_name"
|
||||
android:launchMode="singleTop">
|
||||
<meta-data
|
||||
android:name="android.app.searchable"
|
||||
android:resource="@xml/searchable" />
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.SEARCH" />
|
||||
</intent-filter>
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
</application>
|
||||
</manifest>
|
||||
+67
@@ -0,0 +1,67 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="?android:attr/listPreferredItemHeight"
|
||||
android:padding="6dip">
|
||||
<ImageView
|
||||
android:id="@+id/req_who_icon"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentTop="true"
|
||||
android:layout_alignParentBottom="true"
|
||||
android:layout_marginRight="6dip"
|
||||
android:gravity="left"
|
||||
android:src="@drawable/icon" />
|
||||
<TextView
|
||||
android:id="@+id/req_state_who"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@id/req_who_icon"
|
||||
android:textSize="10dip"
|
||||
android:layout_alignParentRight="false"
|
||||
android:layout_alignParentTop="false"
|
||||
android:layout_alignWithParentIfMissing="true"
|
||||
android:gravity="left"
|
||||
android:text="who" />
|
||||
<TextView
|
||||
android:id="@+id/req_header"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_toRightOf="@id/req_state_who"
|
||||
android:layout_alignParentTop="true"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_alignWithParentIfMissing="true"
|
||||
android:gravity="right"
|
||||
android:text="No summary"
|
||||
android:textSize="10dip"
|
||||
android:textColor="#FFFF00" />
|
||||
<TextView
|
||||
android:id="@+id/req_summary"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@id/req_header"
|
||||
android:layout_toRightOf="@id/req_state_who"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_alignWithParentIfMissing="true"
|
||||
android:gravity="right"
|
||||
android:textSize="10dip"
|
||||
android:text="No summary" />
|
||||
<TextView
|
||||
android:id="@+id/req_description"
|
||||
android:layout_below="@id/req_summary"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_toRightOf="@id/req_state_who"
|
||||
android:layout_alignParentBottom="true"
|
||||
android:layout_alignParentRight="true"
|
||||
android:gravity="right"
|
||||
android:ellipsize="marquee"
|
||||
android:text="No description"
|
||||
android:textSize="10dip" />
|
||||
<ImageView
|
||||
android:id="@+id/req_state_icon"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_toRightOf="@id/req_description"
|
||||
android:layout_marginRight="6dip"/>
|
||||
</RelativeLayout>
|
||||
Vendored
+59
@@ -0,0 +1,59 @@
|
||||
package test
|
||||
|
||||
import android.app.Activity
|
||||
import android.view.View
|
||||
import android.widget.*
|
||||
import kotlinx.android.synthetic.main.layout.*
|
||||
import kotlinx.android.synthetic.main.layout1.*
|
||||
|
||||
class R {
|
||||
class id {
|
||||
companion object {
|
||||
const val item_detail_container = 0
|
||||
const val textView1 = 1
|
||||
const val password = 2
|
||||
const val textView2 = 3
|
||||
const val passwordConfirmation = 4
|
||||
const val login = 5
|
||||
const val passwordField = 6
|
||||
const val passwordCaption = 7
|
||||
const val loginButton = 8
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class MyActivity(): Activity() {
|
||||
val textViewWidget = TextView(this)
|
||||
val editTextWidget = EditText(this)
|
||||
val buttonWidget = Button(this)
|
||||
val textViewWidget2 = TextView(this)
|
||||
val editTextWidget2 = EditText(this)
|
||||
val buttonWidget2 = Button(this)
|
||||
|
||||
override fun findViewById(id: Int): View? {
|
||||
return when (id) {
|
||||
R.id.textView1 -> textViewWidget
|
||||
R.id.password -> editTextWidget
|
||||
R.id.login -> buttonWidget
|
||||
R.id.passwordField -> textViewWidget2
|
||||
R.id.passwordCaption -> editTextWidget2
|
||||
R.id.loginButton -> buttonWidget2
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public fun box(): String{
|
||||
return if (textView1.toString() == "TextView" &&
|
||||
password.toString() == "EditText" &&
|
||||
login.toString() == "Button" &&
|
||||
passwordField.toString() == "TextView" &&
|
||||
passwordCaption.toString() == "EditText" &&
|
||||
loginButton.toString() == "Button")
|
||||
"OK" else ""
|
||||
}
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
return MyActivity().box()
|
||||
}
|
||||
Vendored
+39
@@ -0,0 +1,39 @@
|
||||
package test
|
||||
|
||||
import android.app.Activity
|
||||
import android.view.View
|
||||
import android.widget.*
|
||||
import kotlinx.android.synthetic.main.layout.*
|
||||
import kotlinx.android.synthetic.main.layout1.*
|
||||
|
||||
class R {
|
||||
class id {
|
||||
companion object {
|
||||
const val item_detail_container = 0
|
||||
const val textView1 = 1
|
||||
const val password = 2
|
||||
const val textView2 = 3
|
||||
const val passwordConfirmation = 4
|
||||
const val login = 5
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class MyActivity(): Activity() {
|
||||
val textViewWidget = TextView(this)
|
||||
val editTextWidget = EditText(this)
|
||||
val buttonWidget = Button(this)
|
||||
|
||||
override fun findViewById(id: Int): View? {
|
||||
return when (id) {
|
||||
R.id.textView1 -> textViewWidget
|
||||
R.id.password -> editTextWidget
|
||||
R.id.login -> buttonWidget
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
return "OK"
|
||||
}
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="test"
|
||||
android:versionCode="1"
|
||||
android:versionName="1.0" >
|
||||
|
||||
<uses-permission android:name="android.permission.READ_CONTACTS"/>
|
||||
<uses-sdk
|
||||
android:minSdkVersion="18"
|
||||
android:targetSdkVersion="18" />
|
||||
<permission android:name="android"></permission>
|
||||
|
||||
<application
|
||||
android:allowBackup="true"
|
||||
android:icon="@drawable/ic_launcher"
|
||||
android:label="@string/app_name"
|
||||
android:theme="@style/Theme.Sample" >
|
||||
<activity
|
||||
android:name="com.example.android.basiccontactables.MainActivity"
|
||||
android:label="@string/app_name"
|
||||
android:launchMode="singleTop">
|
||||
<meta-data
|
||||
android:name="android.app.searchable"
|
||||
android:resource="@xml/searchable" />
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.SEARCH" />
|
||||
</intent-filter>
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
</application>
|
||||
</manifest>
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/item_detail_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:context=".ItemDetailActivity"
|
||||
tools:ignore="MergeRootFrame" >
|
||||
|
||||
|
||||
<TextView
|
||||
android:id="@+id/textView1"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Enter your password" />
|
||||
|
||||
<EditText
|
||||
android:id="@+id/password"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:ems="10"
|
||||
android:inputType="textPassword" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/login"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Sign in" />
|
||||
|
||||
</FrameLayout>
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/frameLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:context=".ItemDetailActivity"
|
||||
tools:ignore="MergeRootFrame" >
|
||||
|
||||
|
||||
<TextView
|
||||
android:id="@+id/passwordField"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Enter your password" />
|
||||
|
||||
<EditText
|
||||
android:id="@+id/passwordCaption"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:ems="10"
|
||||
android:inputType="textPassword" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/loginButton"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Sign in" />
|
||||
|
||||
</FrameLayout>
|
||||
Vendored
+45
@@ -0,0 +1,45 @@
|
||||
package test
|
||||
|
||||
import android.app.Activity
|
||||
import android.view.View
|
||||
import android.widget.*
|
||||
import kotlinx.android.synthetic.main.layout.*
|
||||
|
||||
class R {
|
||||
class id {
|
||||
companion object {
|
||||
const val item_detail_container = 0
|
||||
const val textView1 = 1
|
||||
const val password = 2
|
||||
const val textView2 = 3
|
||||
const val passwordConfirmation = 4
|
||||
const val login = 5
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class MyActivity(): Activity() {
|
||||
val textViewWidget = TextView(this)
|
||||
val editTextWidget = EditText(this)
|
||||
val buttonWidget = Button(this)
|
||||
|
||||
override fun findViewById(id: Int): View? {
|
||||
return when (id) {
|
||||
R.id.textView1 -> textViewWidget
|
||||
R.id.password -> editTextWidget
|
||||
R.id.login -> buttonWidget
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
public fun box(): String{
|
||||
return if (textView1.toString() == "TextView" &&
|
||||
password.toString() == "EditText" &&
|
||||
login.toString() == "Button")
|
||||
"OK" else ""
|
||||
}
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
return MyActivity().box()
|
||||
}
|
||||
Vendored
+38
@@ -0,0 +1,38 @@
|
||||
package test
|
||||
|
||||
import android.app.Activity
|
||||
import android.view.View
|
||||
import android.widget.*
|
||||
import kotlinx.android.synthetic.main.layout.*
|
||||
|
||||
class R {
|
||||
class id {
|
||||
companion object {
|
||||
const val item_detail_container = 0
|
||||
const val textView1 = 1
|
||||
const val password = 2
|
||||
const val textView2 = 3
|
||||
const val passwordConfirmation = 4
|
||||
const val login = 5
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class MyActivity(): Activity() {
|
||||
val textViewWidget = TextView(this)
|
||||
val editTextWidget = EditText(this)
|
||||
val buttonWidget = Button(this)
|
||||
|
||||
override fun findViewById(id: Int): View? {
|
||||
return when (id) {
|
||||
R.id.textView1 -> textViewWidget
|
||||
R.id.password -> editTextWidget
|
||||
R.id.login -> buttonWidget
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
return "OK"
|
||||
}
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="test"
|
||||
android:versionCode="1"
|
||||
android:versionName="1.0" >
|
||||
|
||||
<uses-permission android:name="android.permission.READ_CONTACTS"/>
|
||||
<uses-sdk
|
||||
android:minSdkVersion="18"
|
||||
android:targetSdkVersion="18" />
|
||||
<permission android:name="android"></permission>
|
||||
|
||||
<application
|
||||
android:allowBackup="true"
|
||||
android:icon="@drawable/ic_launcher"
|
||||
android:label="@string/app_name"
|
||||
android:theme="@style/Theme.Sample" >
|
||||
<activity
|
||||
android:name="com.example.android.basiccontactables.MainActivity"
|
||||
android:label="@string/app_name"
|
||||
android:launchMode="singleTop">
|
||||
<meta-data
|
||||
android:name="android.app.searchable"
|
||||
android:resource="@xml/searchable" />
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.SEARCH" />
|
||||
</intent-filter>
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
</application>
|
||||
</manifest>
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/item_detail_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:context=".ItemDetailActivity"
|
||||
tools:ignore="MergeRootFrame" >
|
||||
|
||||
|
||||
<TextView
|
||||
android:id="@+id/textView1"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Enter your password" />
|
||||
|
||||
<EditText
|
||||
android:id="@+id/password"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:ems="10"
|
||||
android:inputType="textPassword" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/login"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Sign in" />
|
||||
|
||||
</FrameLayout>
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
package test
|
||||
|
||||
import android.app.Activity
|
||||
import android.view.View
|
||||
import android.widget.*
|
||||
import kotlinx.android.synthetic.main.layout.*
|
||||
import kotlinx.android.synthetic.main.layout.view.*
|
||||
|
||||
class R {
|
||||
class id {
|
||||
companion object {
|
||||
const val container = 0
|
||||
const val login = 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class MyActivity(): Activity() {
|
||||
val containerWidget = object : FrameLayout(this) {
|
||||
val loginWidget = Button(this@MyActivity)
|
||||
|
||||
override fun findViewById(id: Int): View? {
|
||||
return when (id) {
|
||||
R.id.login -> loginWidget
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun findViewById(id: Int): View? {
|
||||
return when (id) {
|
||||
R.id.container -> containerWidget
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
public fun box(): String{
|
||||
return if (container.login.toString() == "Button") "OK" else ""
|
||||
}
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
return MyActivity().box()
|
||||
}
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
package test
|
||||
|
||||
import android.app.Activity
|
||||
import android.view.View
|
||||
import android.widget.*
|
||||
import kotlinx.android.synthetic.main.layout.*
|
||||
import kotlinx.android.synthetic.main.layout.view.*
|
||||
|
||||
class R {
|
||||
class id {
|
||||
companion object {
|
||||
const val container = 0
|
||||
const val login = 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class MyActivity(): Activity() {
|
||||
val containerWidget = object : FrameLayout(this) {
|
||||
val loginWidget = Button(this@MyActivity)
|
||||
}
|
||||
|
||||
override fun findViewById(id: Int): View? {
|
||||
return when (id) {
|
||||
R.id.container -> containerWidget
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
return "OK"
|
||||
}
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="test"
|
||||
android:versionCode="1"
|
||||
android:versionName="1.0" >
|
||||
|
||||
<uses-permission android:name="android.permission.READ_CONTACTS"/>
|
||||
<uses-sdk
|
||||
android:minSdkVersion="18"
|
||||
android:targetSdkVersion="18" />
|
||||
<permission android:name="android"></permission>
|
||||
|
||||
<application
|
||||
android:allowBackup="true"
|
||||
android:icon="@drawable/ic_launcher"
|
||||
android:label="@string/app_name"
|
||||
android:theme="@style/Theme.Sample" >
|
||||
<activity
|
||||
android:name="com.example.android.basiccontactables.MainActivity"
|
||||
android:label="@string/app_name"
|
||||
android:launchMode="singleTop">
|
||||
<meta-data
|
||||
android:name="android.app.searchable"
|
||||
android:resource="@xml/searchable" />
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.SEARCH" />
|
||||
</intent-filter>
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
</application>
|
||||
</manifest>
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/item_detail_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:context=".ItemDetailActivity"
|
||||
tools:ignore="MergeRootFrame" >
|
||||
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/container"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<Button
|
||||
android:id="@+id/login"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Sign in" />
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
</FrameLayout>
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
package test
|
||||
|
||||
import android.app.Activity
|
||||
import kotlinx.android.synthetic.main.layout.*
|
||||
|
||||
fun Activity.a() {
|
||||
val x = login
|
||||
val y = this.login
|
||||
}
|
||||
|
||||
// 2 GETSTATIC test/R\$id\.login
|
||||
// 2 INVOKEVIRTUAL android/app/Activity\.findViewById
|
||||
// 2 CHECKCAST android/widget/Button
|
||||
// 0 _\$_findCachedViewById
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/item_detail_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:context=".ItemDetailActivity"
|
||||
tools:ignore="MergeRootFrame" >
|
||||
|
||||
|
||||
|
||||
<Button
|
||||
android:id="@+id/login"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Sign in" />
|
||||
|
||||
</FrameLayout>
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
package test
|
||||
|
||||
import android.app.Fragment
|
||||
import kotlinx.android.synthetic.main.layout.*
|
||||
|
||||
fun Fragment.a() {
|
||||
val x = login
|
||||
val y = this.login
|
||||
}
|
||||
|
||||
// 2 GETSTATIC test/R\$id\.login
|
||||
// 2 CHECKCAST android/widget/Button
|
||||
// 2 INVOKEVIRTUAL android/app/Fragment\.getView
|
||||
// 2 INVOKEVIRTUAL android/view/View\.findViewById
|
||||
// 0 _\$_findCachedViewById
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/item_detail_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:context=".ItemDetailActivity"
|
||||
tools:ignore="MergeRootFrame" >
|
||||
|
||||
|
||||
|
||||
<Button
|
||||
android:id="@+id/login"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Sign in" />
|
||||
|
||||
</FrameLayout>
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
package test
|
||||
|
||||
import android.app.Activity
|
||||
import android.os.Bundle
|
||||
import java.io.File
|
||||
import kotlinx.android.synthetic.*
|
||||
|
||||
public class MyActivity : Activity() {
|
||||
init { clearFindViewByIdCache() }
|
||||
}
|
||||
|
||||
// 1 public _\$_findCachedViewById
|
||||
// 1 public _\$_clearFindViewByIdCache
|
||||
// 1 INVOKEVIRTUAL test/MyActivity\._\$_clearFindViewByIdCache
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
package test
|
||||
|
||||
import android.app.Activity
|
||||
import android.os.Bundle
|
||||
import java.io.File
|
||||
import kotlinx.android.synthetic.*
|
||||
|
||||
public fun Activity.a() {
|
||||
clearFindViewByIdCache()
|
||||
}
|
||||
|
||||
// 0 clearFindViewByIdCache
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
package test
|
||||
|
||||
import android.app.Activity
|
||||
import android.os.Bundle
|
||||
import java.io.File
|
||||
import kotlinx.android.synthetic.main.layout.*
|
||||
|
||||
public class MyActivity : Activity() {
|
||||
|
||||
}
|
||||
|
||||
fun MyActivity.b() {
|
||||
val x = login
|
||||
val y = this.login
|
||||
}
|
||||
|
||||
// 1 public _\$_findCachedViewById
|
||||
// 1 public _\$_clearFindViewByIdCache
|
||||
// 2 GETSTATIC test/R\$id\.login
|
||||
// 2 INVOKEVIRTUAL test/MyActivity\._\$_findCachedViewById
|
||||
// 2 CHECKCAST android/widget/Button
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/item_detail_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:context=".ItemDetailActivity"
|
||||
tools:ignore="MergeRootFrame" >
|
||||
|
||||
|
||||
|
||||
<Button
|
||||
android:id="@+id/login"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Sign in" />
|
||||
|
||||
</FrameLayout>
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
package test
|
||||
|
||||
import android.app.Fragment
|
||||
import android.os.Bundle
|
||||
import java.io.File
|
||||
import kotlinx.android.synthetic.main.layout.*
|
||||
|
||||
public class MyFragment : Fragment()
|
||||
|
||||
fun MyFragment.b() {
|
||||
val x = login
|
||||
val y = this.login
|
||||
}
|
||||
|
||||
// 1 public _\$_findCachedViewById
|
||||
// 1 public _\$_clearFindViewByIdCache
|
||||
// 1 INVOKEVIRTUAL test/MyFragment\.getView
|
||||
// 2 GETSTATIC test/R\$id\.login
|
||||
// 2 INVOKEVIRTUAL test/MyFragment\._\$_findCachedViewById
|
||||
// 2 CHECKCAST android/widget/Button
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/item_detail_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:context=".ItemDetailActivity"
|
||||
tools:ignore="MergeRootFrame" >
|
||||
|
||||
|
||||
|
||||
<Button
|
||||
android:id="@+id/login"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Sign in" />
|
||||
|
||||
</FrameLayout>
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
package test
|
||||
|
||||
import android.view.View
|
||||
import kotlinx.android.synthetic.main.layout.view.*
|
||||
|
||||
fun View.a() {
|
||||
val x = login
|
||||
val y = this.login
|
||||
}
|
||||
|
||||
// 2 GETSTATIC test/R\$id\.login
|
||||
// 2 INVOKEVIRTUAL android/view/View\.findViewById
|
||||
// 2 CHECKCAST android/widget/Button
|
||||
// 0 _\$_findCachedViewById
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/item_detail_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:context=".ItemDetailActivity"
|
||||
tools:ignore="MergeRootFrame" >
|
||||
|
||||
|
||||
|
||||
<Button
|
||||
android:id="@+id/login"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Sign in" />
|
||||
|
||||
</FrameLayout>
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
package test
|
||||
|
||||
import android.app.Activity
|
||||
import kotlinx.android.synthetic.main.layout.*
|
||||
|
||||
class MyActivity: Activity() {
|
||||
val button = this.MyButton
|
||||
val button2 = MyButton
|
||||
}
|
||||
|
||||
// 1 public _\$_findCachedViewById
|
||||
// 1 public _\$_clearFindViewByIdCache
|
||||
// 2 GETSTATIC test/R\$id\.MyButton
|
||||
// 2 INVOKEVIRTUAL test/MyActivity\._\$_findCachedViewById
|
||||
// 2 CHECKCAST android/widget/Button
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:context=".ItemDetailActivity"
|
||||
tools:ignore="MergeRootFrame" >
|
||||
|
||||
<view
|
||||
class="android.widget.Button"
|
||||
android:id="@+id/MyButton"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Sign in" />
|
||||
|
||||
</FrameLayout>
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
package test
|
||||
|
||||
import android.app.Fragment
|
||||
import kotlinx.android.synthetic.main.layout.*
|
||||
|
||||
class MyFragment: Fragment() {
|
||||
val button = this.MyButton
|
||||
val button2 = MyButton
|
||||
}
|
||||
|
||||
// 1 public _\$_findCachedViewById
|
||||
// 1 public _\$_clearFindViewByIdCache
|
||||
// 1 INVOKEVIRTUAL test/MyFragment\.getView
|
||||
// 2 GETSTATIC test/R\$id\.MyButton
|
||||
// 2 INVOKEVIRTUAL test/MyFragment\._\$_findCachedViewById
|
||||
// 2 CHECKCAST android/widget/Button
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:context=".ItemDetailActivity"
|
||||
tools:ignore="MergeRootFrame" >
|
||||
|
||||
<view
|
||||
class="android.widget.Button"
|
||||
android:id="@+id/MyButton"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Sign in" />
|
||||
|
||||
</FrameLayout>
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
package test
|
||||
|
||||
import android.app.Activity
|
||||
import kotlinx.android.synthetic.main.layout.*
|
||||
|
||||
class MyActivity: Activity() {
|
||||
val button = this.MyButton
|
||||
val button2 = MyButton
|
||||
}
|
||||
|
||||
// 1 public _\$_findCachedViewById
|
||||
// 1 public _\$_clearFindViewByIdCache
|
||||
// 2 GETSTATIC test/R\$id\.MyButton
|
||||
// 2 INVOKEVIRTUAL test/MyActivity\._\$_findCachedViewById
|
||||
// 2 CHECKCAST android/widget/Button
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:context=".ItemDetailActivity"
|
||||
tools:ignore="MergeRootFrame" >
|
||||
|
||||
<android.widget.Button
|
||||
android:id="@+id/MyButton"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Sign in" />
|
||||
|
||||
</FrameLayout>
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
package test
|
||||
|
||||
import android.app.Fragment
|
||||
import kotlinx.android.synthetic.main.layout.*
|
||||
|
||||
class MyFragment: Fragment() {
|
||||
val button = this.MyButton
|
||||
val button2 = MyButton
|
||||
}
|
||||
|
||||
// 1 public _\$_findCachedViewById
|
||||
// 1 public _\$_clearFindViewByIdCache
|
||||
// 1 INVOKEVIRTUAL test/MyFragment\.getView
|
||||
// 2 GETSTATIC test/R\$id\.MyButton
|
||||
// 2 INVOKEVIRTUAL test/MyFragment\._\$_findCachedViewById
|
||||
// 2 CHECKCAST android/widget/Button
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:context=".ItemDetailActivity"
|
||||
tools:ignore="MergeRootFrame" >
|
||||
|
||||
<android.widget.Button
|
||||
android:id="@+id/MyButton"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Sign in" />
|
||||
|
||||
</FrameLayout>
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
package test
|
||||
|
||||
import android.app.Activity
|
||||
import kotlinx.android.synthetic.main.layout.*
|
||||
import kotlinx.android.synthetic.main.layout1.*
|
||||
|
||||
class MyActivity: Activity() {
|
||||
val button = this.login
|
||||
val button1 = this.loginButton
|
||||
}
|
||||
|
||||
// 1 public _\$_findCachedViewById
|
||||
// 1 public _\$_clearFindViewByIdCache
|
||||
// 1 GETSTATIC test/R\$id\.login : I
|
||||
// 1 GETSTATIC test/R\$id\.loginButton : I
|
||||
// 2 INVOKEVIRTUAL test/MyActivity\._\$_findCachedViewById
|
||||
// 2 CHECKCAST android/widget/Button
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/item_detail_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:context=".ItemDetailActivity"
|
||||
tools:ignore="MergeRootFrame" >
|
||||
|
||||
|
||||
<TextView
|
||||
android:id="@+id/textView1"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Enter your password" />
|
||||
|
||||
<EditText
|
||||
android:id="@+id/password"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:ems="10"
|
||||
android:inputType="textPassword" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/login"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Sign in" />
|
||||
|
||||
</FrameLayout>
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/frameLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:context=".ItemDetailActivity"
|
||||
tools:ignore="MergeRootFrame" >
|
||||
|
||||
|
||||
<TextView
|
||||
android:id="@+id/passwordField"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Enter your password" />
|
||||
|
||||
<EditText
|
||||
android:id="@+id/passwordCaption"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:ems="10"
|
||||
android:inputType="textPassword" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/loginButton"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Sign in" />
|
||||
|
||||
</FrameLayout>
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
package test
|
||||
|
||||
import android.app.Activity
|
||||
import android.app.Fragment
|
||||
import kotlinx.android.synthetic.main.layout.*
|
||||
import kotlinx.android.synthetic.main.layout1.*
|
||||
|
||||
class MyActivity: Activity() {
|
||||
val button = this.login
|
||||
}
|
||||
|
||||
class MyFragment: Fragment() {
|
||||
val button1 = this.loginButton
|
||||
}
|
||||
|
||||
// 2 public _\$_findCachedViewById
|
||||
// 2 public _\$_clearFindViewByIdCache
|
||||
// 1 INVOKEVIRTUAL test/MyFragment\.getView
|
||||
// 1 GETSTATIC test/R\$id\.login : I
|
||||
// 1 GETSTATIC test/R\$id\.loginButton : I
|
||||
// 1 INVOKEVIRTUAL test/MyActivity\._\$_findCachedViewById
|
||||
// 1 INVOKEVIRTUAL test/MyFragment\._\$_findCachedViewById
|
||||
// 2 CHECKCAST android/widget/Button
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/item_detail_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:context=".ItemDetailActivity"
|
||||
tools:ignore="MergeRootFrame" >
|
||||
|
||||
|
||||
<TextView
|
||||
android:id="@+id/textView1"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Enter your password" />
|
||||
|
||||
<EditText
|
||||
android:id="@+id/password"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:ems="10"
|
||||
android:inputType="textPassword" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/login"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Sign in" />
|
||||
|
||||
</FrameLayout>
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/frameLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:context=".ItemDetailActivity"
|
||||
tools:ignore="MergeRootFrame" >
|
||||
|
||||
|
||||
<TextView
|
||||
android:id="@+id/passwordField"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Enter your password" />
|
||||
|
||||
<EditText
|
||||
android:id="@+id/passwordCaption"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:ems="10"
|
||||
android:inputType="textPassword" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/loginButton"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Sign in" />
|
||||
|
||||
</FrameLayout>
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
package test
|
||||
|
||||
import android.app.Fragment
|
||||
import java.io.File
|
||||
import kotlinx.android.synthetic.main.layout.*
|
||||
|
||||
public class MyFragment : Fragment() {
|
||||
init {login}
|
||||
}
|
||||
|
||||
public class MyFragment2 : Fragment() {
|
||||
|
||||
override fun onDestroy() {
|
||||
super.onDestroy()
|
||||
}
|
||||
|
||||
public open fun onDestroy(n: Int) {}
|
||||
|
||||
}
|
||||
|
||||
// 2 public onDestroyView\(\)V
|
||||
// 1 INVOKEVIRTUAL test/MyFragment\._\$_clearFindViewByIdCache
|
||||
// 1 INVOKEVIRTUAL test/MyFragment2\._\$_clearFindViewByIdCache
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/item_detail_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:context=".ItemDetailActivity"
|
||||
tools:ignore="MergeRootFrame" >
|
||||
|
||||
|
||||
|
||||
<Button
|
||||
android:id="@+id/login"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Sign in" />
|
||||
|
||||
</FrameLayout>
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/item_detail_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:context=".ItemDetailActivity"
|
||||
tools:ignore="MergeRootFrame" >
|
||||
|
||||
|
||||
|
||||
<Button
|
||||
android:id="@+id/login"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Sign in" />
|
||||
|
||||
</FrameLayout>
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
package test
|
||||
|
||||
import android.app.Activity
|
||||
import android.os.Bundle
|
||||
import java.io.File
|
||||
import kotlinx.android.synthetic.main.layout.*
|
||||
|
||||
public class MyActivity : Activity() {
|
||||
init {login}
|
||||
}
|
||||
|
||||
// 1 public _\$_findCachedViewById
|
||||
// 1 public _\$_clearFindViewByIdCache
|
||||
// 1 GETSTATIC test/R\$id\.login
|
||||
// 1 INVOKEVIRTUAL test/MyActivity\._\$_findCachedViewById
|
||||
// 1 CHECKCAST android/widget/Button
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/item_detail_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:context=".ItemDetailActivity"
|
||||
tools:ignore="MergeRootFrame" >
|
||||
|
||||
|
||||
|
||||
<Button
|
||||
android:id="@+id/login"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Sign in" />
|
||||
|
||||
</FrameLayout>
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
package test
|
||||
|
||||
import android.app.Fragment
|
||||
import java.io.File
|
||||
import kotlinx.android.synthetic.main.layout.*
|
||||
|
||||
public class MyFragment : Fragment() {
|
||||
init {login}
|
||||
}
|
||||
|
||||
// 1 public _\$_findCachedViewById
|
||||
// 1 public _\$_clearFindViewByIdCache
|
||||
// 1 INVOKEVIRTUAL test/MyFragment\.getView
|
||||
// 1 GETSTATIC test/R\$id\.login
|
||||
// 1 INVOKEVIRTUAL test/MyFragment\._\$_findCachedViewById
|
||||
// 1 CHECKCAST android/widget/Button
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/item_detail_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:context=".ItemDetailActivity"
|
||||
tools:ignore="MergeRootFrame" >
|
||||
|
||||
|
||||
|
||||
<fragment
|
||||
android:id="@+id/fragm"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
</FrameLayout>
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
package test
|
||||
|
||||
import android.app.Activity
|
||||
import android.app.Fragment
|
||||
import android.os.Bundle
|
||||
import java.io.File
|
||||
import kotlinx.android.synthetic.main.layout.*
|
||||
|
||||
public class MyActivity : Activity() {
|
||||
init { fragm }
|
||||
}
|
||||
|
||||
public class MyFragment : Fragment() {
|
||||
init { fragm }
|
||||
}
|
||||
|
||||
// 1 INVOKEVIRTUAL android/app/Activity\.getFragmentManager
|
||||
// 1 INVOKEVIRTUAL android/app/Fragment\.getFragmentManager
|
||||
// 2 GETSTATIC test/R\$id\.fragm
|
||||
// 2 INVOKEVIRTUAL android/app/FragmentManager\.findFragmentById
|
||||
// 2 CHECKCAST android/app/Fragment
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/item_detail_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:context=".ItemDetailActivity"
|
||||
tools:ignore="MergeRootFrame" >
|
||||
|
||||
|
||||
|
||||
<Button
|
||||
android:id="@+id/login"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Sign in" />
|
||||
|
||||
</FrameLayout>
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
package test
|
||||
|
||||
import android.view.View
|
||||
import android.app.Activity
|
||||
import kotlinx.android.synthetic.main.layout.view.*
|
||||
|
||||
public class MyActivity : Activity() {
|
||||
init { View(this).login }
|
||||
}
|
||||
|
||||
// 1 public _\$_findCachedViewById
|
||||
// 1 INVOKEVIRTUAL test/MyActivity\.findViewById
|
||||
// 1 public _\$_clearFindViewByIdCache
|
||||
// 1 GETSTATIC test/R\$id\.login
|
||||
// 1 INVOKEVIRTUAL android/view/View\.findViewById
|
||||
// 0 INVOKEVIRTUAL test/MyActivity\._\$_findCachedViewById
|
||||
// 1 CHECKCAST android/widget/Button
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/item_detail_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:context=".ItemDetailActivity"
|
||||
tools:ignore="MergeRootFrame" >
|
||||
|
||||
|
||||
|
||||
<Button
|
||||
android:id="@+id/login"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Sign in" />
|
||||
|
||||
</FrameLayout>
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user