From 85e18a3d73e9c4a622ffe3cd471a223f4176ac98 Mon Sep 17 00:00:00 2001 From: Mikhail Mutcianko Date: Fri, 8 Aug 2014 14:42:23 +0400 Subject: [PATCH] correct interpretation of android id usage mixed with id declarations --- .../resolve/android/AndroidResourceManager.kt | 23 +++++++++++++++---- .../lang/resolve/android/AndroidXmlHandler.kt | 9 ++++---- .../android/CliAndroidUIXmlProcessor.kt | 2 +- .../android/AndroidGotoDeclarationHandler.kt | 4 ---- .../plugin/android/AndroidRenameProcessor.kt | 2 +- .../jet/plugin/android/AndroidXmlVisitor.kt | 8 +++---- .../android/IDEAndroidUIXmlProcessor.kt | 4 ++-- 7 files changed, 31 insertions(+), 21 deletions(-) diff --git a/compiler/frontend.android/src/org/jetbrains/jet/lang/resolve/android/AndroidResourceManager.kt b/compiler/frontend.android/src/org/jetbrains/jet/lang/resolve/android/AndroidResourceManager.kt index 17f797df008..ace59d77544 100644 --- a/compiler/frontend.android/src/org/jetbrains/jet/lang/resolve/android/AndroidResourceManager.kt +++ b/compiler/frontend.android/src/org/jetbrains/jet/lang/resolve/android/AndroidResourceManager.kt @@ -21,17 +21,32 @@ import com.intellij.psi.PsiElement import com.intellij.openapi.project.Project abstract class AndroidResourceManager(val project: Project, val searchPath: String?) { - private val idPrefix = "@+id/" + private val idDeclarationPrefix = "@+id/" + private val idUsagePrefix = "@id/" + public val androidNamespace: String = "android" + public val idAttributeNoNamespace: String = "id" + public val idAttribute: String = androidNamespace + ":" + idAttributeNoNamespace + public val classAttributeNoNamespace: String = "class" + public val classAttribute: String = androidNamespace + ":" + classAttributeNoNamespace abstract fun getLayoutXmlFiles(): Collection abstract fun idToXmlAttribute(id: String): PsiElement? abstract fun renameXmlAttr(elem: PsiElement, newName: String) abstract fun renameProperty(oldName: String, newName: String) - public fun nameToId(name: String): String = idPrefix + name - public fun idToName(id: String): String = id.replace(idPrefix, "") - public fun isResourceId(str: String?): Boolean = str?.startsWith(idPrefix) ?: false + public fun nameToIdDeclaration(name: String): String = idDeclarationPrefix + name + public fun nameToIdUsage(name: String): String = idUsagePrefix + name + public fun idToName(id: String?): String { + return if (isResourceIdDeclaration(id)) id!!.replace(idDeclarationPrefix, "") + else if (isResourceIdUsage(id)) id!!.replace(idUsagePrefix, "") + else throw WrongIdFormat(id) + } + public fun isResourceIdDeclaration(str: String?): Boolean = str?.startsWith(idDeclarationPrefix) ?: false + public fun isResourceIdUsage(str: String?): Boolean = str?.startsWith(idUsagePrefix) ?: false + public fun isResourceDeclarationOrUsage(id: String?): Boolean = isResourceIdDeclaration(id) || isResourceIdUsage(id) abstract fun readManifest(): AndroidManifest inner class NoUIXMLsFound : Exception("No android UI xmls found in $searchPath") + inner class WrongIdFormat(id: String?) : Exception("Id \"$id\" has wrong format") + } diff --git a/compiler/frontend.android/src/org/jetbrains/jet/lang/resolve/android/AndroidXmlHandler.kt b/compiler/frontend.android/src/org/jetbrains/jet/lang/resolve/android/AndroidXmlHandler.kt index c09e4e887fe..70e1df3b3be 100644 --- a/compiler/frontend.android/src/org/jetbrains/jet/lang/resolve/android/AndroidXmlHandler.kt +++ b/compiler/frontend.android/src/org/jetbrains/jet/lang/resolve/android/AndroidXmlHandler.kt @@ -20,7 +20,7 @@ import org.xml.sax.helpers.DefaultHandler import org.xml.sax.Attributes import java.util.HashMap -class AndroidXmlHandler(val elementCallback: (String, String) -> Unit) : DefaultHandler() { +class AndroidXmlHandler(val resourceManager: AndroidResourceManager, val elementCallback: (String, String) -> Unit) : DefaultHandler() { override fun startDocument() { super.startDocument() @@ -32,10 +32,9 @@ class AndroidXmlHandler(val elementCallback: (String, String) -> Unit) : Default override fun startElement(uri: String, localName: String, qName: String, attributes: Attributes) { val hashMap = attributes.toMap() - val s = hashMap["id"] - val idPrefix = "@+id/" - val className = hashMap["class"] ?: localName - if (s != null && s.startsWith(idPrefix)) elementCallback(s.replace(idPrefix, ""), className) + val s = hashMap[resourceManager.idAttributeNoNamespace] + val className = hashMap[resourceManager.classAttributeNoNamespace] ?: localName + if (resourceManager.isResourceDeclarationOrUsage(s)) elementCallback(resourceManager.idToName(s), className) } override fun endElement(uri: String?, localName: String, qName: String) { diff --git a/compiler/frontend.android/src/org/jetbrains/jet/lang/resolve/android/CliAndroidUIXmlProcessor.kt b/compiler/frontend.android/src/org/jetbrains/jet/lang/resolve/android/CliAndroidUIXmlProcessor.kt index af1c3ad024a..82f85e36d8d 100644 --- a/compiler/frontend.android/src/org/jetbrains/jet/lang/resolve/android/CliAndroidUIXmlProcessor.kt +++ b/compiler/frontend.android/src/org/jetbrains/jet/lang/resolve/android/CliAndroidUIXmlProcessor.kt @@ -33,7 +33,7 @@ class CliAndroidUIXmlProcessor(project: Project, override val searchPath: String override fun parseSingleFileImpl(file: PsiFile): String { val ids: MutableCollection = ArrayList() - val handler = AndroidXmlHandler({ id, wClass -> ids.add(AndroidWidget(id, wClass)) }) + val handler = AndroidXmlHandler(resourceManager, { id, wClass -> ids.add(AndroidWidget(id, wClass)) }) try { resourceManager.saxParser.parse(file.getVirtualFile()?.getInputStream()!!, handler) return produceKotlinProperties(KotlinStringWriter(), ids).toString() diff --git a/idea/src/org/jetbrains/jet/plugin/android/AndroidGotoDeclarationHandler.kt b/idea/src/org/jetbrains/jet/plugin/android/AndroidGotoDeclarationHandler.kt index 2dd0facb641..acef71394a7 100644 --- a/idea/src/org/jetbrains/jet/plugin/android/AndroidGotoDeclarationHandler.kt +++ b/idea/src/org/jetbrains/jet/plugin/android/AndroidGotoDeclarationHandler.kt @@ -23,14 +23,10 @@ import com.intellij.openapi.actionSystem.DataContext import com.intellij.openapi.components.ServiceManager import org.jetbrains.jet.lang.resolve.android.AndroidUIXmlProcessor import com.intellij.psi.impl.source.tree.LeafPsiElement -import com.intellij.psi.util.PsiTreeUtil -import com.intellij.psi.PsiReferenceExpression import org.jetbrains.jet.plugin.references.JetSimpleNameReference import org.jetbrains.jet.lang.psi.JetSimpleNameExpression import org.jetbrains.jet.lang.psi.JetProperty import com.intellij.psi.impl.light.LightElement -import org.jetbrains.android.augment.AndroidInternalRClass -import com.intellij.psi.xml.XmlAttributeValue import com.intellij.psi.xml.XmlAttribute public class AndroidGotoDeclarationHandler : GotoDeclarationHandler { diff --git a/idea/src/org/jetbrains/jet/plugin/android/AndroidRenameProcessor.kt b/idea/src/org/jetbrains/jet/plugin/android/AndroidRenameProcessor.kt index fb141fabbb7..8be95f63a3d 100644 --- a/idea/src/org/jetbrains/jet/plugin/android/AndroidRenameProcessor.kt +++ b/idea/src/org/jetbrains/jet/plugin/android/AndroidRenameProcessor.kt @@ -55,7 +55,7 @@ public class AndroidRenameProcessor : RenamePsiElementProcessor() { val processor = ServiceManager.getService(jetProperty.getProject(), javaClass()) val resourceManager = processor!!.resourceManager val attr = resourceManager.idToXmlAttribute(oldName) as XmlAttribute - allRenames[XmlAttributeValueWrapper(attr.getValueElement()!!)] = resourceManager.nameToId(newName!!) + allRenames[XmlAttributeValueWrapper(attr.getValueElement()!!)] = resourceManager.nameToIdDeclaration(newName!!) val name = AndroidResourceUtil.getResourceNameByReferenceText(newName) for (resField in AndroidResourceUtil.findIdFields(attr)) { allRenames.put(resField, AndroidResourceUtil.getFieldNameByResourceName(name!!)) diff --git a/idea/src/org/jetbrains/jet/plugin/android/AndroidXmlVisitor.kt b/idea/src/org/jetbrains/jet/plugin/android/AndroidXmlVisitor.kt index 8557cf2302c..03f2d6fd314 100644 --- a/idea/src/org/jetbrains/jet/plugin/android/AndroidXmlVisitor.kt +++ b/idea/src/org/jetbrains/jet/plugin/android/AndroidXmlVisitor.kt @@ -21,8 +21,9 @@ import com.intellij.psi.PsiElement import com.intellij.psi.xml.XmlElement import com.intellij.psi.xml.XmlTag import com.intellij.psi.xml.XmlAttribute +import org.jetbrains.jet.lang.resolve.android.AndroidResourceManager -class AndroidXmlVisitor(val elementCallback: (String, String, XmlAttribute) -> Unit) : XmlElementVisitor() { +class AndroidXmlVisitor(val resourceManager: AndroidResourceManager, val elementCallback: (String, String, XmlAttribute) -> Unit) : XmlElementVisitor() { override fun visitElement(element: PsiElement) { element.acceptChildren(this) @@ -33,10 +34,9 @@ class AndroidXmlVisitor(val elementCallback: (String, String, XmlAttribute) -> U } override fun visitXmlTag(tag: XmlTag?) { - val idPrefix = "@+id/" - val attribute = tag?.getAttribute("android:id") + val attribute = tag?.getAttribute(resourceManager.idAttribute) if (attribute != null && attribute.getValue() != null) { - elementCallback(attribute.getValue()!!.replace(idPrefix, ""), tag!!.getLocalName(), attribute) + elementCallback(resourceManager.idToName(attribute.getValue()), tag!!.getLocalName(), attribute) } tag?.acceptChildren(this) } diff --git a/idea/src/org/jetbrains/jet/plugin/android/IDEAndroidUIXmlProcessor.kt b/idea/src/org/jetbrains/jet/plugin/android/IDEAndroidUIXmlProcessor.kt index b282929502a..ebe42c007b7 100644 --- a/idea/src/org/jetbrains/jet/plugin/android/IDEAndroidUIXmlProcessor.kt +++ b/idea/src/org/jetbrains/jet/plugin/android/IDEAndroidUIXmlProcessor.kt @@ -39,10 +39,10 @@ class IDEAndroidUIXmlProcessor(project: Project) : AndroidUIXmlProcessor(project override fun parseSingleFileImpl(file: PsiFile): String { val ids: MutableCollection = ArrayList() resourceManager.resetAttributeCache() - file.accept(AndroidXmlVisitor { id, wClass, valueElement -> + file.accept(AndroidXmlVisitor(resourceManager, { id, wClass, valueElement -> ids.add(AndroidWidget(id, wClass)) resourceManager.addMapping(id, valueElement) - }) + })) return produceKotlinProperties(KotlinStringWriter(), ids).toString() } }