fix excess xml parsing when renaming resources

- rebuild resource name -> xml attribute mappings same time as rebuilding synthetic properties
- update mappings during rename
This commit is contained in:
Mikhail Mutcianko
2014-08-04 12:29:27 +04:00
committed by Yan Zhulanow
parent 9f20c36959
commit 37c851cafc
5 changed files with 20 additions and 34 deletions
@@ -23,10 +23,14 @@ import com.intellij.openapi.actionSystem.DataContext
import com.intellij.openapi.components.ServiceManager import com.intellij.openapi.components.ServiceManager
import org.jetbrains.jet.lang.resolve.android.AndroidUIXmlProcessor import org.jetbrains.jet.lang.resolve.android.AndroidUIXmlProcessor
import com.intellij.psi.impl.source.tree.LeafPsiElement import com.intellij.psi.impl.source.tree.LeafPsiElement
import com.intellij.psi.util.PsiTreeUtil
import com.intellij.psi.PsiReferenceExpression
public class AndroidGotoDeclarationHandler : GotoDeclarationHandler { public class AndroidGotoDeclarationHandler : GotoDeclarationHandler {
override fun getGotoDeclarationTargets(sourceElement: PsiElement?, offset: Int, editor: Editor?): Array<PsiElement>? { override fun getGotoDeclarationTargets(sourceElement: PsiElement?, offset: Int, editor: Editor?): Array<PsiElement>? {
// FIXME: find a way to filter out more bad sourceElements before they hit idToXmlAttribute() resulting in cache rebuild
if (sourceElement is LeafPsiElement) { if (sourceElement is LeafPsiElement) {
val refExp = PsiTreeUtil.getParentOfType(sourceElement, javaClass<PsiReferenceExpression>())
val parser = ServiceManager.getService(sourceElement.getProject(), javaClass<AndroidUIXmlProcessor>()) val parser = ServiceManager.getService(sourceElement.getProject(), javaClass<AndroidUIXmlProcessor>())
val psiElement = parser?.resourceManager?.idToXmlAttribute(sourceElement.getText()) val psiElement = parser?.resourceManager?.idToXmlAttribute(sourceElement.getText())
if (psiElement != null) { if (psiElement != null) {
@@ -78,6 +78,7 @@ public class AndroidRenameProcessor : RenamePsiElementProcessor() {
for (prop in matchedProps) { for (prop in matchedProps) {
allRenames[prop] = newPropName allRenames[prop] = newPropName
} }
processor.resourceManager.renameProperty(oldPropName!!, newPropName)
} }
private fun renameLightClassField(field: LightElement, newName: String?, allRenames: MutableMap<PsiElement, String>, scope: SearchScope) { private fun renameLightClassField(field: LightElement, newName: String?, allRenames: MutableMap<PsiElement, String>, scope: SearchScope) {
@@ -20,8 +20,9 @@ import com.intellij.psi.XmlElementVisitor
import com.intellij.psi.PsiElement import com.intellij.psi.PsiElement
import com.intellij.psi.xml.XmlElement import com.intellij.psi.xml.XmlElement
import com.intellij.psi.xml.XmlTag 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) { override fun visitElement(element: PsiElement) {
element.acceptChildren(this) element.acceptChildren(this)
@@ -35,7 +36,7 @@ class AndroidXmlVisitor(val elementCallback: (String, String) -> Unit) : XmlElem
val idPrefix = "@+id/" val idPrefix = "@+id/"
val attribute = tag?.getAttribute("android:id") val attribute = tag?.getAttribute("android:id")
if (attribute != null && attribute.getValue() != null) { if (attribute != null && attribute.getValue() != null) {
elementCallback(attribute.getValue()!!.replace(idPrefix, ""), tag!!.getLocalName()) elementCallback(attribute.getValue()!!.replace(idPrefix, ""), tag!!.getLocalName(), attribute)
} }
tag?.acceptChildren(this) tag?.acceptChildren(this)
} }
@@ -21,53 +21,30 @@ import org.jetbrains.jet.lang.resolve.android.AndroidResourceManagerBase
import com.intellij.psi.PsiElement import com.intellij.psi.PsiElement
import java.util.HashMap import java.util.HashMap
import com.intellij.psi.xml.XmlAttribute 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) { public class IDEAndroidResourceManager(project: Project, searchPath: String?) : AndroidResourceManagerBase(project, searchPath) {
private val idToXmlAttributeCache = HashMap<String, PsiElement>() private val idToXmlAttributeCache = HashMap<String, PsiElement>()
;{ public fun addMapping(name: String, attr: XmlAttribute) {
setupElementCache() idToXmlAttributeCache[name] = attr
} }
private fun setupElementCache() { public fun resetAttributeCache() {
idToXmlAttributeCache.clear() 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? { override fun idToXmlAttribute(id: String): PsiElement? {
val element = idToXmlAttributeCache[id] val element = idToXmlAttributeCache[id]
// element not in cache - files might have changed
if (element == null) {
setupElementCache()
return idToXmlAttributeCache[id]
}
return element return element
} }
override fun renameXmlAttr(elem: PsiElement, newName: String) { override fun renameXmlAttr(elem: PsiElement, newName: String) {
val xmlAttr = elem as XmlAttribute val xmlAttr = elem as XmlAttribute
idToXmlAttributeCache.remove(xmlAttr.getName()) idToXmlAttributeCache.remove(xmlAttr.getName())
idToXmlAttributeCache[newName] = xmlAttr idToXmlAttributeCache[newName] = xmlAttr
} }
override fun renameProperty(oldName: String, newName: String) { override fun renameProperty(oldName: String, newName: String) {
val oldElem = idToXmlAttributeCache[oldName] val oldElem = idToXmlAttributeCache[oldName]
idToXmlAttributeCache.remove(oldName) idToXmlAttributeCache.remove(oldName)
@@ -22,13 +22,12 @@ import java.util.ArrayList
import com.intellij.psi.PsiFile import com.intellij.psi.PsiFile
import org.jetbrains.jet.lang.resolve.android.AndroidWidget import org.jetbrains.jet.lang.resolve.android.AndroidWidget
import org.jetbrains.jet.lang.resolve.android.KotlinStringWriter import org.jetbrains.jet.lang.resolve.android.KotlinStringWriter
import org.jetbrains.jet.lang.resolve.android.AndroidResourceManager
class IDEAndroidUIXmlProcessor(project: Project) : AndroidUIXmlProcessor(project) { class IDEAndroidUIXmlProcessor(project: Project) : AndroidUIXmlProcessor(project) {
override val searchPath: String? = project.getBasePath() + "/res/layout/" override val searchPath: String? = project.getBasePath() + "/res/layout/"
override var androidAppPackage: String = "" override var androidAppPackage: String = ""
override val resourceManager: AndroidResourceManager = IDEAndroidResourceManager(project, searchPath) override val resourceManager: IDEAndroidResourceManager = IDEAndroidResourceManager(project, searchPath)
override protected fun lazySetup() { override protected fun lazySetup() {
if (listenerSetUp) return if (listenerSetUp) return
@@ -39,7 +38,11 @@ class IDEAndroidUIXmlProcessor(project: Project) : AndroidUIXmlProcessor(project
override fun parseSingleFileImpl(file: PsiFile): String { override fun parseSingleFileImpl(file: PsiFile): String {
val ids: MutableCollection<AndroidWidget> = ArrayList() val ids: MutableCollection<AndroidWidget> = 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() return produceKotlinProperties(KotlinStringWriter(), ids).toString()
} }
} }