Fix "unresolved widget fqname" bug in Gradle

This commit is contained in:
Yan Zhulanow
2015-09-17 13:10:10 +03:00
parent 07b77432de
commit b73f91d16b
15 changed files with 58 additions and 46 deletions
@@ -29,8 +29,7 @@ import com.intellij.mock.MockApplication
import com.intellij.openapi.Disposable
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.components.ServiceManager
import com.intellij.openapi.extensions.Extensions
import com.intellij.openapi.extensions.ExtensionsArea
import com.intellij.openapi.extensions.*
import com.intellij.openapi.fileTypes.FileTypeExtensionPoint
import com.intellij.openapi.fileTypes.PlainTextFileType
import com.intellij.openapi.project.Project
@@ -18,11 +18,13 @@ package org.jetbrains.kotlin.android.synthetic
import com.intellij.mock.MockProject
import com.intellij.openapi.components.ServiceManager
import com.intellij.openapi.extensions.Extensions
import com.intellij.openapi.project.Project
import org.jetbrains.kotlin.analyzer.ModuleInfo
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.CliAndroidLayoutXmlFileManager
import org.jetbrains.kotlin.android.synthetic.res.CliSyntheticFileGenerator
@@ -37,6 +39,7 @@ 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.ExternalDeclarationsProvider
import org.jetbrains.kotlin.extensions.StorageComponentContainerContributor
import org.jetbrains.kotlin.psi.JetFile
@@ -75,7 +78,7 @@ public class AndroidCommandLineProcessor : CommandLineProcessor {
public class CliAndroidDeclarationsProvider(private val project: Project) : ExternalDeclarationsProvider {
override fun getExternalDeclarations(moduleInfo: ModuleInfo?): Collection<JetFile> {
val parser = ServiceManager.getService(project, javaClass<SyntheticFileGenerator>()) as? CliSyntheticFileGenerator
val parser = ServiceManager.getService(project, SyntheticFileGenerator::class.java) as? CliSyntheticFileGenerator
return parser?.getSyntheticFiles() ?: listOf()
}
}
@@ -89,12 +92,13 @@ public class AndroidComponentRegistrar : ComponentRegistrar {
if (androidResPath != null && androidManifest != null) {
val xmlProcessor = CliSyntheticFileGenerator(project, androidManifest, androidResPath)
project.registerService(javaClass<SyntheticFileGenerator>(), xmlProcessor)
project.registerService(javaClass<AndroidLayoutXmlFileManager>(), CliAndroidLayoutXmlFileManager(project, androidManifest, androidResPath))
project.registerService(SyntheticFileGenerator::class.java, xmlProcessor)
project.registerService(AndroidLayoutXmlFileManager::class.java, CliAndroidLayoutXmlFileManager(project, androidManifest, androidResPath))
ExternalDeclarationsProvider.registerExtension(project, CliAndroidDeclarationsProvider(project))
ExpressionCodegenExtension.registerExtension(project, AndroidExpressionCodegenExtension())
StorageComponentContainerContributor.registerExtension(project, AndroidExtensionPropertiesComponentContainerContributor())
Extensions.getRootArea().getExtensionPoint(DefaultErrorMessages.Extension.EP_NAME).registerExtension(DefaultErrorMessagesAndroid())
ClassBuilderInterceptorExtension.registerExtension(project, AndroidOnDestroyClassBuilderInterceptorExtension())
}
}
@@ -17,9 +17,6 @@
package org.jetbrains.kotlin.android.synthetic
import com.intellij.openapi.util.Key
import org.jetbrains.kotlin.android.synthetic.res.AndroidFragment
import org.jetbrains.kotlin.android.synthetic.res.AndroidResource
import org.jetbrains.kotlin.android.synthetic.res.AndroidWidget
import org.jetbrains.kotlin.lexer.JetKeywordToken
import org.jetbrains.kotlin.lexer.JetTokens
@@ -53,8 +50,8 @@ public object AndroidConst {
val IGNORED_XML_WIDGET_TYPES = setOf("requestFocus", "merge", "tag", "check", "blink")
val ESCAPED_IDENTIFIERS = (JetTokens.KEYWORDS.getTypes() + JetTokens.SOFT_KEYWORDS.getTypes())
.map { it as? JetKeywordToken }.filterNotNull().map { it.getValue() }.toSet()
val ESCAPED_IDENTIFIERS = (JetTokens.KEYWORDS.types + JetTokens.SOFT_KEYWORDS.types)
.map { it as? JetKeywordToken }.filterNotNull().map { it.value }.toSet()
val FQNAME_RESOLVE_PACKAGES = listOf("android.widget", "android.webkit", "android.view")
}
@@ -74,16 +71,4 @@ public fun isWidgetTypeIgnored(xmlType: String): Boolean {
fun escapeAndroidIdentifier(id: String): String {
return if (id in AndroidConst.ESCAPED_IDENTIFIERS) "`$id`" else id
}
public fun parseAndroidResource(id: String, tag: String, fqNameResolver: (String) -> String?): AndroidResource {
return when (tag) {
"fragment" -> AndroidFragment(id)
"include" -> AndroidWidget(id, AndroidConst.VIEW_FQNAME)
else -> {
val fqName = fqNameResolver(tag)
val invalidType = if (fqName != null) null else tag
AndroidWidget(id, fqName ?: AndroidConst.VIEW_FQNAME, invalidType)
}
}
}
@@ -16,7 +16,9 @@
package org.jetbrains.kotlin.android.synthetic.diagnostic
import com.intellij.openapi.project.Project
import org.jetbrains.kotlin.android.synthetic.AndroidConst
import org.jetbrains.kotlin.android.synthetic.CliAndroidDeclarationsProvider
import org.jetbrains.kotlin.android.synthetic.res.SyntheticFileGenerator
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.resolve.calls.checkers.CallChecker
@@ -24,6 +26,7 @@ import org.jetbrains.kotlin.resolve.calls.context.BasicCallResolutionContext
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
import org.jetbrains.kotlin.resolve.constants.StringValue
import org.jetbrains.kotlin.android.synthetic.diagnostic.ErrorsAndroid.*
import org.jetbrains.kotlin.extensions.ExternalDeclarationsProvider
public class AndroidExtensionPropertiesCallChecker : CallChecker {
override fun <F : CallableDescriptor> check(resolvedCall: ResolvedCall<F>, context: BasicCallResolutionContext) {
@@ -44,5 +47,4 @@ public class AndroidExtensionPropertiesCallChecker : CallChecker {
val warning = if (erroneousType.contains('.')) SYNTHETIC_UNRESOLVED_WIDGET_TYPE else SYNTHETIC_INVALID_WIDGET_TYPE
context.trace.report(warning.on(expression, erroneousType))
}
}
@@ -29,8 +29,9 @@ public class DefaultErrorMessagesAndroid : DefaultErrorMessages.Extension {
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''.",
"Widget has an unresolved type ''{0}'', and thus it was upcasted to ''android.view.View''",
Renderers.TO_STRING)
}
}
@@ -23,9 +23,8 @@ import com.intellij.psi.PsiFile
import java.io.ByteArrayInputStream
import com.intellij.psi.impl.PsiElementFinderImpl
import com.intellij.psi.search.GlobalSearchScope
import org.jetbrains.kotlin.android.synthetic.AndroidConst
import org.jetbrains.kotlin.android.synthetic.AndroidXmlHandler
import org.jetbrains.kotlin.android.synthetic.parseAndroidResource
import org.jetbrains.kotlin.load.java.JavaClassFinder
import org.jetbrains.kotlin.psi.JetFile
public open class CliSyntheticFileGenerator(
@@ -78,6 +77,13 @@ public open class CliSyntheticFileGenerator(
return false
}
override fun parseAndroidWidget(id: String, tag: String, fqNameResolver: (String) -> String?): AndroidResource {
val fqName = fqNameResolver(tag)
val invalidType = if (fqName != null) null else tag
val type = fqName ?: (if ('.' in tag) tag else AndroidConst.VIEW_FQNAME)
return AndroidWidget(id, type, invalidType)
}
private companion object {
private val LOG: Logger = Logger.getInstance(javaClass)
}
@@ -17,7 +17,6 @@
package org.jetbrains.kotlin.android.synthetic.res
import com.intellij.openapi.project.Project
import com.intellij.psi.PsiClass
import com.intellij.psi.PsiFile
import com.intellij.psi.PsiManager
import com.intellij.psi.util.CachedValue
@@ -123,7 +122,7 @@ public abstract class SyntheticFileGenerator(protected val project: Project) {
private fun KotlinStringWriter.writeSyntheticProperty(receiver: String, resource: AndroidResource, stubCall: String) {
val className = if (isFromSupportV4Package(receiver)) resource.supportClassName else resource.className
val cast = if (resource.className != "View") " as? $className" else ""
val cast = if (resource.className != AndroidConst.VIEW_FQNAME) " as? $className" else ""
val body = arrayListOf("return $stubCall$cast")
// Annotation on wrong widget type
@@ -165,6 +164,16 @@ public abstract class SyntheticFileGenerator(protected val project: Project) {
return null
}
protected fun parseAndroidResource(id: String, tag: String, fqNameResolver: (String) -> String?): AndroidResource {
return when (tag) {
"fragment" -> AndroidFragment(id)
"include" -> AndroidWidget(id, AndroidConst.VIEW_FQNAME)
else -> parseAndroidWidget(id, tag, fqNameResolver)
}
}
protected abstract fun parseAndroidWidget(id: String, tag: String, fqNameResolver: (String) -> String?): AndroidResource
protected fun supportV4Available(): Boolean = checkIfClassExist(AndroidConst.SUPPORT_FRAGMENT_FQNAME)
protected fun filterDuplicates(resources: List<AndroidResource>): List<AndroidResource> {
@@ -3,8 +3,8 @@ package kotlinx.android.synthetic.test
import kotlin.internal.flexible.ft
val android.app.Activity.button: ft<android.view.View, android.view.View?>
get() = findViewById(0) as? android.view.View
get() = findViewById(0)
val android.app.Fragment.button: ft<android.view.View, android.view.View?>
get() = getView().findViewById(0) as? android.view.View
get() = getView().findViewById(0)
@@ -3,10 +3,10 @@ package kotlinx.android.synthetic.test
import kotlin.internal.flexible.ft
val android.app.Activity.textView1: ft<android.view.View, android.view.View?>
get() = findViewById(0) as? android.view.View
get() = findViewById(0)
val android.app.Fragment.textView1: ft<android.view.View, android.view.View?>
get() = getView().findViewById(0) as? android.view.View
get() = getView().findViewById(0)
val android.app.Activity.textView2: ft<android.widget.TextView, android.widget.TextView?>
get() = findViewById(0) as? android.widget.TextView
@@ -3,10 +3,10 @@ package kotlinx.android.synthetic.test
import kotlin.internal.flexible.ft
val android.app.Activity.button: ft<android.view.View, android.view.View?>
get() = findViewById(0) as? android.view.View
get() = findViewById(0)
val android.app.Fragment.button: ft<android.view.View, android.view.View?>
get() = getView().findViewById(0) as? android.view.View
get() = getView().findViewById(0)
val android.app.Activity.button2: ft<android.widget.Button, android.widget.Button?>
get() = findViewById(0) as? android.widget.Button
@@ -3,10 +3,10 @@ package kotlinx.android.synthetic.test
import kotlin.internal.flexible.ft
val android.app.Activity.includeTag: ft<android.view.View, android.view.View?>
get() = findViewById(0) as? android.view.View
get() = findViewById(0)
val android.app.Fragment.includeTag: ft<android.view.View, android.view.View?>
get() = getView().findViewById(0) as? android.view.View
get() = getView().findViewById(0)
val android.app.Activity.fragmentTag: ft<android.app.Fragment, android.app.Fragment?>
get() = getFragmentManager().findFragmentById(0) as? android.app.Fragment
@@ -3,13 +3,13 @@ package kotlinx.android.synthetic.test
import kotlin.internal.flexible.ft
val android.app.Activity.includeTag: ft<android.view.View, android.view.View?>
get() = findViewById(0) as? android.view.View
get() = findViewById(0)
val android.app.Fragment.includeTag: ft<android.view.View, android.view.View?>
get() = getView().findViewById(0) as? android.view.View
get() = getView().findViewById(0)
val android.support.v4.app.Fragment.includeTag: ft<android.view.View, android.view.View?>
get() = getView().findViewById(0) as? android.view.View
get() = getView().findViewById(0)
val android.app.Activity.fragmentTag: ft<android.app.Fragment, android.app.Fragment?>
get() = getFragmentManager().findFragmentById(0) as? android.app.Fragment
@@ -3,10 +3,10 @@ package kotlinx.android.synthetic.test
import kotlin.internal.flexible.ft
@kotlin.internal.flexible.InvalidWidgetType("a.b.c")
val android.app.Activity.MyView: ft<android.view.View, android.view.View?>
get() = findViewById(0) as? android.view.View
val android.app.Activity.MyView: ft<a.b.c, a.b.c?>
get() = findViewById(0) as? a.b.c
@kotlin.internal.flexible.InvalidWidgetType("a.b.c")
val android.app.Fragment.MyView: ft<android.view.View, android.view.View?>
get() = getView().findViewById(0) as? android.view.View
val android.app.Fragment.MyView: ft<a.b.c, a.b.c?>
get() = getView().findViewById(0) as? a.b.c
@@ -4,9 +4,9 @@ import kotlin.internal.flexible.ft
@kotlin.internal.flexible.InvalidWidgetType("KeyboardView")
val android.app.Activity.MyKeyboardView: ft<android.view.View, android.view.View?>
get() = findViewById(0) as? android.view.View
get() = findViewById(0)
@kotlin.internal.flexible.InvalidWidgetType("KeyboardView")
val android.app.Fragment.MyKeyboardView: ft<android.view.View, android.view.View?>
get() = getView().findViewById(0) as? android.view.View
get() = getView().findViewById(0)
@@ -25,8 +25,8 @@ import com.intellij.psi.util.CachedValueProvider.Result
import org.jetbrains.kotlin.android.synthetic.AndroidConst
import org.jetbrains.kotlin.android.synthetic.idea.AndroidPsiTreeChangePreprocessor
import org.jetbrains.kotlin.android.synthetic.idea.AndroidXmlVisitor
import org.jetbrains.kotlin.android.synthetic.parseAndroidResource
import org.jetbrains.kotlin.android.synthetic.res.AndroidResource
import org.jetbrains.kotlin.android.synthetic.res.AndroidWidget
import org.jetbrains.kotlin.android.synthetic.res.SyntheticFileGenerator
import org.jetbrains.kotlin.psi.JetFile
@@ -62,6 +62,12 @@ class IDESyntheticFileGenerator(val module: Module) : SyntheticFileGenerator(mod
return filterDuplicates(widgets)
}
override fun parseAndroidWidget(id: String, tag: String, fqNameResolver: (String) -> String?): AndroidResource {
val fqName = fqNameResolver(tag)
val invalidType = if (fqName != null) null else tag
return AndroidWidget(id, fqName ?: AndroidConst.VIEW_FQNAME, invalidType)
}
override fun checkIfClassExist(fqName: String): Boolean {
val moduleScope = module.getModuleWithDependenciesAndLibrariesScope(false)
return JavaPsiFacade.getInstance(module.project).findClass(fqName, moduleScope) != null