Lookup XML attribute using the property (for a particular layout)
This commit is contained in:
+2
-1
@@ -21,7 +21,8 @@ import com.intellij.openapi.util.Key
|
|||||||
public object AndroidConst {
|
public object AndroidConst {
|
||||||
val ANDROID_USER_PACKAGE: Key<String> = Key.create<String>("ANDROID_USER_PACKAGE")
|
val ANDROID_USER_PACKAGE: Key<String> = Key.create<String>("ANDROID_USER_PACKAGE")
|
||||||
val SYNTHETIC_FILENAME: String = "ANDROIDXML"
|
val SYNTHETIC_FILENAME: String = "ANDROIDXML"
|
||||||
val SYNTHETIC_PACKAGE: String = "kotlinx.android.synthetic."
|
val SYNTHETIC_PACKAGE: String = "kotlinx.android.synthetic"
|
||||||
|
val SYNTHETIC_PACKAGE_PATH_LENGTH = SYNTHETIC_PACKAGE.count { it == '.' } + 1
|
||||||
|
|
||||||
val ANDROID_NAMESPACE: String = "android"
|
val ANDROID_NAMESPACE: String = "android"
|
||||||
val ID_ATTRIBUTE_NO_NAMESPACE: String = "id"
|
val ID_ATTRIBUTE_NO_NAMESPACE: String = "id"
|
||||||
|
|||||||
+2
-1
@@ -26,12 +26,13 @@ import com.intellij.openapi.vfs.*
|
|||||||
import com.intellij.openapi.components.*
|
import com.intellij.openapi.components.*
|
||||||
import com.intellij.openapi.extensions.*
|
import com.intellij.openapi.extensions.*
|
||||||
import com.intellij.openapi.module.*
|
import com.intellij.openapi.module.*
|
||||||
|
import org.jetbrains.kotlin.psi.JetProperty
|
||||||
|
|
||||||
public abstract class AndroidResourceManager(val project: Project) {
|
public abstract class AndroidResourceManager(val project: Project) {
|
||||||
|
|
||||||
public abstract val androidModuleInfo: AndroidModuleInfo?
|
public abstract val androidModuleInfo: AndroidModuleInfo?
|
||||||
|
|
||||||
public open fun idToXmlAttribute(id: String): PsiElement? = null
|
public open fun propertyToXmlAttribute(property: JetProperty): PsiElement? = null
|
||||||
|
|
||||||
public fun getLayoutXmlFiles(): Map<String, List<PsiFile>> {
|
public fun getLayoutXmlFiles(): Map<String, List<PsiFile>> {
|
||||||
val info = androidModuleInfo
|
val info = androidModuleInfo
|
||||||
|
|||||||
+2
-2
@@ -84,7 +84,7 @@ public abstract class AndroidUIXmlProcessor(protected val project: Project) {
|
|||||||
|
|
||||||
public fun parse(generateCommonFiles: Boolean = true): List<String> {
|
public fun parse(generateCommonFiles: Boolean = true): List<String> {
|
||||||
val commonFiles = if (generateCommonFiles) {
|
val commonFiles = if (generateCommonFiles) {
|
||||||
val clearCacheFile = renderLayoutFile("kotlinx.android.synthetic") {} +
|
val clearCacheFile = renderLayoutFile(AndroidConst.SYNTHETIC_PACKAGE) {} +
|
||||||
renderClearCacheFunction("Activity") + renderClearCacheFunction("Fragment")
|
renderClearCacheFunction("Activity") + renderClearCacheFunction("Fragment")
|
||||||
listOf(clearCacheFile, FLEXIBLE_TYPE_FILE)
|
listOf(clearCacheFile, FLEXIBLE_TYPE_FILE)
|
||||||
} else listOf()
|
} else listOf()
|
||||||
@@ -132,7 +132,7 @@ public abstract class AndroidUIXmlProcessor(protected val project: Project) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun PsiFile.genSyntheticPackageName(): String {
|
private fun PsiFile.genSyntheticPackageName(): String {
|
||||||
return AndroidConst.SYNTHETIC_PACKAGE + getName().substringBefore('.')
|
return AndroidConst.SYNTHETIC_PACKAGE + "." + getName().substringBefore('.')
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun KotlinStringWriter.writeSyntheticProperty(receiver: String, widget: AndroidWidget, stubCall: String) {
|
private fun KotlinStringWriter.writeSyntheticProperty(receiver: String, widget: AndroidWidget, stubCall: String) {
|
||||||
|
|||||||
+12
-6
@@ -27,6 +27,9 @@ import com.intellij.psi.xml.XmlAttribute
|
|||||||
import org.jetbrains.android.util.AndroidResourceUtil
|
import org.jetbrains.android.util.AndroidResourceUtil
|
||||||
import java.util.ArrayList
|
import java.util.ArrayList
|
||||||
import com.intellij.find.findUsages.JavaVariableFindUsagesOptions
|
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.plugin.findUsages.handlers.KotlinFindUsagesHandlerDecorator
|
||||||
import org.jetbrains.kotlin.psi.JetNamedDeclaration
|
import org.jetbrains.kotlin.psi.JetNamedDeclaration
|
||||||
import org.jetbrains.kotlin.psi.JetProperty
|
import org.jetbrains.kotlin.psi.JetProperty
|
||||||
@@ -52,9 +55,10 @@ class AndroidFindMemberUsagesHandler(
|
|||||||
assert(isAndroidSyntheticElement(declaration))
|
assert(isAndroidSyntheticElement(declaration))
|
||||||
|
|
||||||
val property = declaration as JetProperty
|
val property = declaration as JetProperty
|
||||||
val name = property.getName()!!
|
val moduleInfo = declaration.getModuleInfo() as? ModuleSourceInfo ?: return super.getPrimaryElements()
|
||||||
val parser = ServiceManager.getService(declaration.getProject(), javaClass<AndroidUIXmlProcessor>())
|
val parser = ModuleServiceManager.getService(moduleInfo.module, javaClass<AndroidUIXmlProcessor>())
|
||||||
val psiElement = parser?.resourceManager?.idToXmlAttribute(name) as? XmlAttribute
|
|
||||||
|
val psiElement = parser?.resourceManager?.propertyToXmlAttribute(property) as? XmlAttribute
|
||||||
if (psiElement != null && psiElement.getValueElement() != null) {
|
if (psiElement != null && psiElement.getValueElement() != null) {
|
||||||
return array(psiElement.getValueElement()!!)
|
return array(psiElement.getValueElement()!!)
|
||||||
}
|
}
|
||||||
@@ -69,9 +73,11 @@ class AndroidFindMemberUsagesHandler(
|
|||||||
override fun getSecondaryElements(): Array<PsiElement> {
|
override fun getSecondaryElements(): Array<PsiElement> {
|
||||||
assert(isAndroidSyntheticElement(declaration))
|
assert(isAndroidSyntheticElement(declaration))
|
||||||
|
|
||||||
val name = (declaration as JetProperty).getName()!!
|
val property = declaration as JetProperty
|
||||||
val parser = ServiceManager.getService(declaration.getProject(), javaClass<AndroidUIXmlProcessor>())
|
val moduleInfo = declaration.getModuleInfo() as? ModuleSourceInfo ?: return super.getPrimaryElements()
|
||||||
val psiElement = parser?.resourceManager?.idToXmlAttribute(name) as? XmlAttribute
|
val parser = ModuleServiceManager.getService(moduleInfo.module, javaClass<AndroidUIXmlProcessor>())
|
||||||
|
|
||||||
|
val psiElement = parser?.resourceManager?.propertyToXmlAttribute(property) as? XmlAttribute
|
||||||
if (psiElement != null) {
|
if (psiElement != null) {
|
||||||
val res = ArrayList<PsiElement>()
|
val res = ArrayList<PsiElement>()
|
||||||
val fields = AndroidResourceUtil.findIdFields(psiElement)
|
val fields = AndroidResourceUtil.findIdFields(psiElement)
|
||||||
|
|||||||
+9
-13
@@ -35,20 +35,16 @@ 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>? {
|
||||||
if (sourceElement is LeafPsiElement && sourceElement.getParent() is JetSimpleNameExpression) {
|
if (sourceElement is LeafPsiElement && sourceElement.getParent() is JetSimpleNameExpression) {
|
||||||
val resolved = JetSimpleNameReference(sourceElement.getParent() as JetSimpleNameExpression).resolve()
|
val resolved = JetSimpleNameReference(sourceElement.getParent() as JetSimpleNameExpression).resolve()
|
||||||
if (resolved == null) return null
|
val property = resolved as? JetProperty ?: 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 parser = ModuleServiceManager.getService(moduleInfo.module, javaClass<AndroidUIXmlProcessor>())
|
val moduleInfo = sourceElement.getModuleInfo()
|
||||||
val psiElement = parser.resourceManager.idToXmlAttribute(name) as? XmlAttribute
|
if (moduleInfo !is ModuleSourceInfo) return null
|
||||||
if (psiElement != null) {
|
|
||||||
return array(psiElement.getValueElement())
|
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
|
return null
|
||||||
|
|||||||
+3
-5
@@ -84,7 +84,7 @@ public class AndroidRenameProcessor : RenamePsiElementProcessor() {
|
|||||||
scope: SearchScope
|
scope: SearchScope
|
||||||
) {
|
) {
|
||||||
if (element != null && element.namedUnwrappedElement is JetProperty) {
|
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) {
|
else if (element is XmlAttributeValue) {
|
||||||
renameAttributeValue(element, newName, allRenames, scope)
|
renameAttributeValue(element, newName, allRenames, scope)
|
||||||
@@ -97,16 +97,14 @@ public class AndroidRenameProcessor : RenamePsiElementProcessor() {
|
|||||||
private fun renameSyntheticProperty(
|
private fun renameSyntheticProperty(
|
||||||
jetProperty: JetProperty,
|
jetProperty: JetProperty,
|
||||||
newName: String,
|
newName: String,
|
||||||
allRenames: MutableMap<PsiElement, String>,
|
allRenames: MutableMap<PsiElement, String>
|
||||||
scope: SearchScope
|
|
||||||
) {
|
) {
|
||||||
val oldName = jetProperty.getName()
|
|
||||||
val module = jetProperty.getModule()
|
val module = jetProperty.getModule()
|
||||||
if (module == null) return
|
if (module == null) return
|
||||||
|
|
||||||
val processor = ModuleServiceManager.getService(module, javaClass<AndroidUIXmlProcessor>())
|
val processor = ModuleServiceManager.getService(module, javaClass<AndroidUIXmlProcessor>())
|
||||||
val resourceManager = processor.resourceManager
|
val resourceManager = processor.resourceManager
|
||||||
val attr = resourceManager.idToXmlAttribute(oldName) as XmlAttribute
|
val attr = resourceManager.propertyToXmlAttribute(jetProperty) as XmlAttribute
|
||||||
allRenames[XmlAttributeValueWrapper(attr.getValueElement())] = nameToIdDeclaration(newName)
|
allRenames[XmlAttributeValueWrapper(attr.getValueElement())] = nameToIdDeclaration(newName)
|
||||||
val name = AndroidResourceUtil.getResourceNameByReferenceText(newName)
|
val name = AndroidResourceUtil.getResourceNameByReferenceText(newName)
|
||||||
for (resField in AndroidResourceUtil.findIdFields(attr)) {
|
for (resField in AndroidResourceUtil.findIdFields(attr)) {
|
||||||
|
|||||||
+23
-8
@@ -19,32 +19,47 @@ package org.jetbrains.kotlin.plugin.android
|
|||||||
import com.intellij.openapi.module.Module
|
import com.intellij.openapi.module.Module
|
||||||
import com.intellij.psi.PsiElement
|
import com.intellij.psi.PsiElement
|
||||||
import org.jetbrains.android.facet.AndroidFacet
|
import org.jetbrains.android.facet.AndroidFacet
|
||||||
|
import org.jetbrains.kotlin.lang.resolve.android.AndroidConst
|
||||||
import kotlin.properties.Delegates
|
import kotlin.properties.Delegates
|
||||||
import org.jetbrains.kotlin.plugin.android.AndroidXmlVisitor
|
import org.jetbrains.kotlin.plugin.android.AndroidXmlVisitor
|
||||||
import org.jetbrains.kotlin.lang.resolve.android.AndroidResourceManager
|
import org.jetbrains.kotlin.lang.resolve.android.AndroidResourceManager
|
||||||
import org.jetbrains.kotlin.lang.resolve.android.AndroidModuleInfo
|
import org.jetbrains.kotlin.lang.resolve.android.AndroidModuleInfo
|
||||||
|
import org.jetbrains.kotlin.psi.JetProperty
|
||||||
|
|
||||||
public class IDEAndroidResourceManager(val module: Module) : AndroidResourceManager(module.getProject()) {
|
public class IDEAndroidResourceManager(val module: Module) : AndroidResourceManager(module.getProject()) {
|
||||||
|
|
||||||
override val androidModuleInfo: AndroidModuleInfo? by Delegates.lazy { module.androidFacet?.toAndroidModuleInfo() }
|
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
|
var ret: PsiElement? = null
|
||||||
for (file in getLayoutXmlFiles().values().flatMap { it }) {
|
val visitor = AndroidXmlVisitor { retId, wClass, valueElement ->
|
||||||
file.accept(AndroidXmlVisitor({ retId, wClass, valueElement ->
|
if (retId == propertyName) ret = valueElement
|
||||||
if (retId == id) ret = valueElement
|
|
||||||
}))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
layoutFiles.first().accept(visitor)
|
||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
|
|
||||||
private val Module.androidFacet: AndroidFacet?
|
private val Module.androidFacet: AndroidFacet?
|
||||||
get() = AndroidFacet.getInstance(this)
|
get() = AndroidFacet.getInstance(this)
|
||||||
|
|
||||||
private fun AndroidFacet.toAndroidModuleInfo(): AndroidModuleInfo {
|
private fun AndroidFacet.toAndroidModuleInfo(): AndroidModuleInfo? {
|
||||||
val applicationPackage = getManifest().getPackage().toString()
|
val applicationPackage = getManifest()?.getPackage()?.toString()
|
||||||
val mainResDirectory = getAllResourceDirectories().firstOrNull()?.getPath()
|
val mainResDirectory = getAllResourceDirectories().firstOrNull()?.getPath()
|
||||||
return AndroidModuleInfo(applicationPackage, mainResDirectory)
|
|
||||||
|
return if (applicationPackage != null) {
|
||||||
|
AndroidModuleInfo(applicationPackage, mainResDirectory)
|
||||||
|
}
|
||||||
|
else null
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user