From 37c851cafc2a75a6a0454c54cfef3b47a210a917 Mon Sep 17 00:00:00 2001 From: Mikhail Mutcianko Date: Mon, 4 Aug 2014 12:29:27 +0400 Subject: [PATCH] fix excess xml parsing when renaming resources - rebuild resource name -> xml attribute mappings same time as rebuilding synthetic properties - update mappings during rename --- .../android/AndroidGotoDeclarationHandler.kt | 4 +++ .../plugin/android/AndroidRenameProcessor.kt | 1 + .../jet/plugin/android/AndroidXmlVisitor.kt | 5 +-- .../android/IDEAndroidResourceManager.kt | 35 ++++--------------- .../android/IDEAndroidUIXmlProcessor.kt | 9 +++-- 5 files changed, 20 insertions(+), 34 deletions(-) diff --git a/idea/src/org/jetbrains/jet/plugin/android/AndroidGotoDeclarationHandler.kt b/idea/src/org/jetbrains/jet/plugin/android/AndroidGotoDeclarationHandler.kt index fdcc6d2e59c..022da6845c9 100644 --- a/idea/src/org/jetbrains/jet/plugin/android/AndroidGotoDeclarationHandler.kt +++ b/idea/src/org/jetbrains/jet/plugin/android/AndroidGotoDeclarationHandler.kt @@ -23,10 +23,14 @@ 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 public class AndroidGotoDeclarationHandler : GotoDeclarationHandler { override fun getGotoDeclarationTargets(sourceElement: PsiElement?, offset: Int, editor: Editor?): Array? { + // FIXME: find a way to filter out more bad sourceElements before they hit idToXmlAttribute() resulting in cache rebuild if (sourceElement is LeafPsiElement) { + val refExp = PsiTreeUtil.getParentOfType(sourceElement, javaClass()) val parser = ServiceManager.getService(sourceElement.getProject(), javaClass()) val psiElement = parser?.resourceManager?.idToXmlAttribute(sourceElement.getText()) if (psiElement != null) { diff --git a/idea/src/org/jetbrains/jet/plugin/android/AndroidRenameProcessor.kt b/idea/src/org/jetbrains/jet/plugin/android/AndroidRenameProcessor.kt index f8926b086b7..fb141fabbb7 100644 --- a/idea/src/org/jetbrains/jet/plugin/android/AndroidRenameProcessor.kt +++ b/idea/src/org/jetbrains/jet/plugin/android/AndroidRenameProcessor.kt @@ -78,6 +78,7 @@ public class AndroidRenameProcessor : RenamePsiElementProcessor() { for (prop in matchedProps) { allRenames[prop] = newPropName } + processor.resourceManager.renameProperty(oldPropName!!, newPropName) } private fun renameLightClassField(field: LightElement, newName: String?, allRenames: MutableMap, scope: SearchScope) { diff --git a/idea/src/org/jetbrains/jet/plugin/android/AndroidXmlVisitor.kt b/idea/src/org/jetbrains/jet/plugin/android/AndroidXmlVisitor.kt index 5ffb43963db..8557cf2302c 100644 --- a/idea/src/org/jetbrains/jet/plugin/android/AndroidXmlVisitor.kt +++ b/idea/src/org/jetbrains/jet/plugin/android/AndroidXmlVisitor.kt @@ -20,8 +20,9 @@ import com.intellij.psi.XmlElementVisitor import com.intellij.psi.PsiElement import com.intellij.psi.xml.XmlElement import com.intellij.psi.xml.XmlTag +import com.intellij.psi.xml.XmlAttribute -class AndroidXmlVisitor(val elementCallback: (String, String) -> Unit) : XmlElementVisitor() { +class AndroidXmlVisitor(val elementCallback: (String, String, XmlAttribute) -> Unit) : XmlElementVisitor() { override fun visitElement(element: PsiElement) { element.acceptChildren(this) @@ -35,7 +36,7 @@ class AndroidXmlVisitor(val elementCallback: (String, String) -> Unit) : XmlElem val idPrefix = "@+id/" val attribute = tag?.getAttribute("android:id") if (attribute != null && attribute.getValue() != null) { - elementCallback(attribute.getValue()!!.replace(idPrefix, ""), tag!!.getLocalName()) + elementCallback(attribute.getValue()!!.replace(idPrefix, ""), tag!!.getLocalName(), attribute) } tag?.acceptChildren(this) } diff --git a/idea/src/org/jetbrains/jet/plugin/android/IDEAndroidResourceManager.kt b/idea/src/org/jetbrains/jet/plugin/android/IDEAndroidResourceManager.kt index 96d7db081bc..9eb00df2e08 100644 --- a/idea/src/org/jetbrains/jet/plugin/android/IDEAndroidResourceManager.kt +++ b/idea/src/org/jetbrains/jet/plugin/android/IDEAndroidResourceManager.kt @@ -21,53 +21,30 @@ import org.jetbrains.jet.lang.resolve.android.AndroidResourceManagerBase import com.intellij.psi.PsiElement import java.util.HashMap import com.intellij.psi.xml.XmlAttribute -import com.intellij.psi.xml.XmlFile -import com.intellij.psi.XmlElementVisitor -import com.intellij.psi.xml.XmlTag public class IDEAndroidResourceManager(project: Project, searchPath: String?) : AndroidResourceManagerBase(project, searchPath) { private val idToXmlAttributeCache = HashMap() - ;{ - setupElementCache() + public fun addMapping(name: String, attr: XmlAttribute) { + idToXmlAttributeCache[name] = attr } - private fun setupElementCache() { + public fun resetAttributeCache() { idToXmlAttributeCache.clear() - for (file in getLayoutXmlFiles()) { - if (file is XmlFile) { - file.accept(object : XmlElementVisitor() { - override fun visitElement(element: PsiElement) { - element.acceptChildren(this) - } - override fun visitXmlTag(tag: XmlTag?) { - val attribute = tag?.getAttribute("android:id") - val s = attribute?.getValue() - if (attribute != null && s != null && isResourceId(s)) { - idToXmlAttributeCache[idToName(s)] = attribute - } - tag?.acceptChildren(this) - } - }) - } - } - } + override fun idToXmlAttribute(id: String): PsiElement? { val element = idToXmlAttributeCache[id] - // element not in cache - files might have changed - if (element == null) { - setupElementCache() - return idToXmlAttributeCache[id] - } return element } + override fun renameXmlAttr(elem: PsiElement, newName: String) { val xmlAttr = elem as XmlAttribute idToXmlAttributeCache.remove(xmlAttr.getName()) idToXmlAttributeCache[newName] = xmlAttr } + override fun renameProperty(oldName: String, newName: String) { val oldElem = idToXmlAttributeCache[oldName] idToXmlAttributeCache.remove(oldName) diff --git a/idea/src/org/jetbrains/jet/plugin/android/IDEAndroidUIXmlProcessor.kt b/idea/src/org/jetbrains/jet/plugin/android/IDEAndroidUIXmlProcessor.kt index ef55d6130e3..b282929502a 100644 --- a/idea/src/org/jetbrains/jet/plugin/android/IDEAndroidUIXmlProcessor.kt +++ b/idea/src/org/jetbrains/jet/plugin/android/IDEAndroidUIXmlProcessor.kt @@ -22,13 +22,12 @@ import java.util.ArrayList import com.intellij.psi.PsiFile import org.jetbrains.jet.lang.resolve.android.AndroidWidget import org.jetbrains.jet.lang.resolve.android.KotlinStringWriter -import org.jetbrains.jet.lang.resolve.android.AndroidResourceManager class IDEAndroidUIXmlProcessor(project: Project) : AndroidUIXmlProcessor(project) { override val searchPath: String? = project.getBasePath() + "/res/layout/" override var androidAppPackage: String = "" - override val resourceManager: AndroidResourceManager = IDEAndroidResourceManager(project, searchPath) + override val resourceManager: IDEAndroidResourceManager = IDEAndroidResourceManager(project, searchPath) override protected fun lazySetup() { if (listenerSetUp) return @@ -39,7 +38,11 @@ class IDEAndroidUIXmlProcessor(project: Project) : AndroidUIXmlProcessor(project override fun parseSingleFileImpl(file: PsiFile): String { val ids: MutableCollection = ArrayList() - file.accept(AndroidXmlVisitor({ id, wClass -> ids.add(AndroidWidget(id, wClass)) })) + resourceManager.resetAttributeCache() + file.accept(AndroidXmlVisitor { id, wClass, valueElement -> + ids.add(AndroidWidget(id, wClass)) + resourceManager.addMapping(id, valueElement) + }) return produceKotlinProperties(KotlinStringWriter(), ids).toString() } }