Lookup XML attribute using the property (for a particular layout)

This commit is contained in:
Yan Zhulanow
2015-03-20 22:20:28 +03:00
parent a4dc6870dc
commit 0a96c2c148
7 changed files with 53 additions and 36 deletions
@@ -27,6 +27,9 @@ import com.intellij.psi.xml.XmlAttribute
import org.jetbrains.android.util.AndroidResourceUtil
import java.util.ArrayList
import com.intellij.find.findUsages.JavaVariableFindUsagesOptions
import com.intellij.openapi.module.ModuleServiceManager
import org.jetbrains.kotlin.idea.caches.resolve.ModuleSourceInfo
import org.jetbrains.kotlin.idea.caches.resolve.getModuleInfo
import org.jetbrains.kotlin.plugin.findUsages.handlers.KotlinFindUsagesHandlerDecorator
import org.jetbrains.kotlin.psi.JetNamedDeclaration
import org.jetbrains.kotlin.psi.JetProperty
@@ -52,9 +55,10 @@ class AndroidFindMemberUsagesHandler(
assert(isAndroidSyntheticElement(declaration))
val property = declaration as JetProperty
val name = property.getName()!!
val parser = ServiceManager.getService(declaration.getProject(), javaClass<AndroidUIXmlProcessor>())
val psiElement = parser?.resourceManager?.idToXmlAttribute(name) as? XmlAttribute
val moduleInfo = declaration.getModuleInfo() as? ModuleSourceInfo ?: return super.getPrimaryElements()
val parser = ModuleServiceManager.getService(moduleInfo.module, javaClass<AndroidUIXmlProcessor>())
val psiElement = parser?.resourceManager?.propertyToXmlAttribute(property) as? XmlAttribute
if (psiElement != null && psiElement.getValueElement() != null) {
return array(psiElement.getValueElement()!!)
}
@@ -69,9 +73,11 @@ class AndroidFindMemberUsagesHandler(
override fun getSecondaryElements(): Array<PsiElement> {
assert(isAndroidSyntheticElement(declaration))
val name = (declaration as JetProperty).getName()!!
val parser = ServiceManager.getService(declaration.getProject(), javaClass<AndroidUIXmlProcessor>())
val psiElement = parser?.resourceManager?.idToXmlAttribute(name) as? XmlAttribute
val property = declaration as JetProperty
val moduleInfo = declaration.getModuleInfo() as? ModuleSourceInfo ?: return super.getPrimaryElements()
val parser = ModuleServiceManager.getService(moduleInfo.module, javaClass<AndroidUIXmlProcessor>())
val psiElement = parser?.resourceManager?.propertyToXmlAttribute(property) as? XmlAttribute
if (psiElement != null) {
val res = ArrayList<PsiElement>()
val fields = AndroidResourceUtil.findIdFields(psiElement)
@@ -35,20 +35,16 @@ public class AndroidGotoDeclarationHandler : GotoDeclarationHandler {
override fun getGotoDeclarationTargets(sourceElement: PsiElement?, offset: Int, editor: Editor?): Array<PsiElement>? {
if (sourceElement is LeafPsiElement && sourceElement.getParent() is JetSimpleNameExpression) {
val resolved = JetSimpleNameReference(sourceElement.getParent() as JetSimpleNameExpression).resolve()
if (resolved == null) return null
val name = if (resolved is JetProperty) {
resolved.getName()
}
else null
if (name != null) {
val moduleInfo = sourceElement.getModuleInfo()
if (moduleInfo !is ModuleSourceInfo) return null
val property = resolved as? JetProperty ?: return null
val parser = ModuleServiceManager.getService(moduleInfo.module, javaClass<AndroidUIXmlProcessor>())
val psiElement = parser.resourceManager.idToXmlAttribute(name) as? XmlAttribute
if (psiElement != null) {
return array(psiElement.getValueElement())
}
val moduleInfo = sourceElement.getModuleInfo()
if (moduleInfo !is ModuleSourceInfo) return null
val parser = ModuleServiceManager.getService(moduleInfo.module, javaClass<AndroidUIXmlProcessor>())
val psiElement = parser.resourceManager.propertyToXmlAttribute(property) as? XmlAttribute
val attributeValue = psiElement?.getValueElement()
if (attributeValue != null) {
return array(attributeValue)
}
}
return null
@@ -84,7 +84,7 @@ public class AndroidRenameProcessor : RenamePsiElementProcessor() {
scope: SearchScope
) {
if (element != null && element.namedUnwrappedElement is JetProperty) {
renameSyntheticProperty(element.namedUnwrappedElement as JetProperty, newName, allRenames, scope)
renameSyntheticProperty(element.namedUnwrappedElement as JetProperty, newName, allRenames)
}
else if (element is XmlAttributeValue) {
renameAttributeValue(element, newName, allRenames, scope)
@@ -97,16 +97,14 @@ public class AndroidRenameProcessor : RenamePsiElementProcessor() {
private fun renameSyntheticProperty(
jetProperty: JetProperty,
newName: String,
allRenames: MutableMap<PsiElement, String>,
scope: SearchScope
allRenames: MutableMap<PsiElement, String>
) {
val oldName = jetProperty.getName()
val module = jetProperty.getModule()
if (module == null) return
val processor = ModuleServiceManager.getService(module, javaClass<AndroidUIXmlProcessor>())
val resourceManager = processor.resourceManager
val attr = resourceManager.idToXmlAttribute(oldName) as XmlAttribute
val attr = resourceManager.propertyToXmlAttribute(jetProperty) as XmlAttribute
allRenames[XmlAttributeValueWrapper(attr.getValueElement())] = nameToIdDeclaration(newName)
val name = AndroidResourceUtil.getResourceNameByReferenceText(newName)
for (resField in AndroidResourceUtil.findIdFields(attr)) {
@@ -19,32 +19,47 @@ package org.jetbrains.kotlin.plugin.android
import com.intellij.openapi.module.Module
import com.intellij.psi.PsiElement
import org.jetbrains.android.facet.AndroidFacet
import org.jetbrains.kotlin.lang.resolve.android.AndroidConst
import kotlin.properties.Delegates
import org.jetbrains.kotlin.plugin.android.AndroidXmlVisitor
import org.jetbrains.kotlin.lang.resolve.android.AndroidResourceManager
import org.jetbrains.kotlin.lang.resolve.android.AndroidModuleInfo
import org.jetbrains.kotlin.psi.JetProperty
public class IDEAndroidResourceManager(val module: Module) : AndroidResourceManager(module.getProject()) {
override val androidModuleInfo: AndroidModuleInfo? by Delegates.lazy { module.androidFacet?.toAndroidModuleInfo() }
override fun idToXmlAttribute(id: String): PsiElement? {
override fun propertyToXmlAttribute(property: JetProperty): PsiElement? {
val fqPath = property.getFqName()?.pathSegments() ?: return null
if (fqPath.size() <= AndroidConst.SYNTHETIC_PACKAGE_PATH_LENGTH) return null
val layoutPackageName = fqPath[AndroidConst.SYNTHETIC_PACKAGE_PATH_LENGTH].asString()
val layoutFiles = getLayoutXmlFiles()[layoutPackageName]
if (layoutFiles == null || layoutFiles.isEmpty()) return null
val propertyName = property.getName()
var ret: PsiElement? = null
for (file in getLayoutXmlFiles().values().flatMap { it }) {
file.accept(AndroidXmlVisitor({ retId, wClass, valueElement ->
if (retId == id) ret = valueElement
}))
val visitor = AndroidXmlVisitor { retId, wClass, valueElement ->
if (retId == propertyName) ret = valueElement
}
layoutFiles.first().accept(visitor)
return ret
}
private val Module.androidFacet: AndroidFacet?
get() = AndroidFacet.getInstance(this)
private fun AndroidFacet.toAndroidModuleInfo(): AndroidModuleInfo {
val applicationPackage = getManifest().getPackage().toString()
private fun AndroidFacet.toAndroidModuleInfo(): AndroidModuleInfo? {
val applicationPackage = getManifest()?.getPackage()?.toString()
val mainResDirectory = getAllResourceDirectories().firstOrNull()?.getPath()
return AndroidModuleInfo(applicationPackage, mainResDirectory)
return if (applicationPackage != null) {
AndroidModuleInfo(applicationPackage, mainResDirectory)
}
else null
}
}