Fix Android extensions import rename

#KT-17890 Fixed
This commit is contained in:
Vyacheslav Gerasimov
2017-07-04 21:34:11 +03:00
parent ee53e81e8e
commit f59859842a
4 changed files with 38 additions and 19 deletions
@@ -79,8 +79,12 @@ class KtSimpleNameReference(expression: KtSimpleNameExpression) : KtSimpleRefere
} }
override fun isReferenceTo(element: PsiElement?): Boolean { override fun isReferenceTo(element: PsiElement?): Boolean {
if (element != null && !canBeReferenceTo(element)) { if (element != null) {
return false if (!canBeReferenceTo(element)) return false
for (extension in Extensions.getArea(element.project).getExtensionPoint(SimpleNameReferenceExtension.EP_NAME).extensions) {
if (extension.isReferenceTo(this, element)) return true
}
} }
return super.isReferenceTo(element) return super.isReferenceTo(element)
@@ -27,5 +27,7 @@ interface SimpleNameReferenceExtension {
ExtensionPointName.create("org.jetbrains.kotlin.simpleNameReferenceExtension") ExtensionPointName.create("org.jetbrains.kotlin.simpleNameReferenceExtension")
} }
fun isReferenceTo(reference: KtSimpleNameReference, element: PsiElement): Boolean
fun handleElementRename(reference: KtSimpleNameReference, psiFactory: KtPsiFactory, newElementName: String): PsiElement? fun handleElementRename(reference: KtSimpleNameReference, psiFactory: KtPsiFactory, newElementName: String): PsiElement?
} }
@@ -18,18 +18,21 @@ package org.jetbrains.kotlin.android.synthetic.idea
import com.intellij.psi.PsiElement import com.intellij.psi.PsiElement
import com.intellij.psi.xml.XmlAttributeValue import com.intellij.psi.xml.XmlAttributeValue
import org.jetbrains.android.dom.wrappers.ValueResourceElementWrapper import com.intellij.psi.xml.XmlFile
import org.jetbrains.android.facet.AndroidFacet
import org.jetbrains.android.util.AndroidResourceUtil import org.jetbrains.android.util.AndroidResourceUtil
import org.jetbrains.kotlin.android.synthetic.AndroidConst import org.jetbrains.kotlin.android.synthetic.AndroidConst
import org.jetbrains.kotlin.android.synthetic.androidIdToName import org.jetbrains.kotlin.android.synthetic.androidIdToName
import org.jetbrains.kotlin.idea.references.KtSimpleNameReference import org.jetbrains.kotlin.idea.references.KtSimpleNameReference
import org.jetbrains.kotlin.plugin.references.SimpleNameReferenceExtension import org.jetbrains.kotlin.plugin.references.SimpleNameReferenceExtension
import org.jetbrains.kotlin.psi.KtDotQualifiedExpression import org.jetbrains.kotlin.psi.KtDotQualifiedExpression
import org.jetbrains.kotlin.psi.KtProperty
import org.jetbrains.kotlin.psi.KtPsiFactory import org.jetbrains.kotlin.psi.KtPsiFactory
class AndroidSimpleNameReferenceExtension : SimpleNameReferenceExtension { class AndroidSimpleNameReferenceExtension : SimpleNameReferenceExtension {
override fun isReferenceTo(reference: KtSimpleNameReference, element: PsiElement): Boolean =
element is XmlFile && reference.isReferenceToXmlFile(element)
private fun isLayoutPackageIdentifier(reference: KtSimpleNameReference): Boolean { private fun isLayoutPackageIdentifier(reference: KtSimpleNameReference): Boolean {
val probablyVariant = reference.element?.parent as? KtDotQualifiedExpression ?: return false val probablyVariant = reference.element?.parent as? KtDotQualifiedExpression ?: return false
val probablyKAS = probablyVariant.receiverExpression as? KtDotQualifiedExpression ?: return false val probablyKAS = probablyVariant.receiverExpression as? KtDotQualifiedExpression ?: return false
@@ -43,9 +46,29 @@ class AndroidSimpleNameReferenceExtension : SimpleNameReferenceExtension {
return psiFactory.createNameIdentifier(newSyntheticPropertyName.name) return psiFactory.createNameIdentifier(newSyntheticPropertyName.name)
} }
else if (isLayoutPackageIdentifier(reference)) { else if (isLayoutPackageIdentifier(reference)) {
return psiFactory.createSimpleName(newElementName.substringBeforeLast(".xml")).getIdentifier() return psiFactory.createSimpleName(newElementName.removeSuffix(".xml")).getIdentifier()
} }
return null return null
} }
private fun KtSimpleNameReference.isReferenceToXmlFile(xmlFile: XmlFile): Boolean {
if (!isLayoutPackageIdentifier(this)) {
return false
}
if (xmlFile.name.removeSuffix(".xml") != element.getReferencedName()) {
return false
}
val virtualFile = xmlFile.virtualFile ?: return false
val layoutDir = virtualFile.parent
if (layoutDir.name != "layout" && !layoutDir.name.startsWith("layout-")) {
return false
}
val resourceDirectories = AndroidFacet.getInstance(element)?.allResourceDirectories ?: return false
val resourceDirectory = virtualFile.parent?.parent ?: return false
return resourceDirectories.any { it == resourceDirectory }
}
} }
@@ -16,10 +16,6 @@
package org.jetbrains.kotlin.android package org.jetbrains.kotlin.android
import com.intellij.codeInsight.TargetElementUtil
import com.intellij.psi.impl.source.tree.injected.InjectedLanguageUtil
import com.intellij.refactoring.rename.RenameProcessor
import com.intellij.psi.impl.source.xml.XmlAttributeValueImpl
import com.intellij.psi.xml.XmlFile import com.intellij.psi.xml.XmlFile
import org.jetbrains.kotlin.android.synthetic.AndroidConst import org.jetbrains.kotlin.android.synthetic.AndroidConst
import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.psi.KtFile
@@ -32,17 +28,11 @@ abstract class AbstractAndroidLayoutRenameTest : KotlinAndroidTestCase() {
copyResourceDirectoryForTest(path) copyResourceDirectoryForTest(path)
val virtualFile = myFixture.copyFileToProject(path + getTestName(true) + ".kt", "src/" + getTestName(true) + ".kt") val virtualFile = myFixture.copyFileToProject(path + getTestName(true) + ".kt", "src/" + getTestName(true) + ".kt")
myFixture.configureFromExistingVirtualFile(virtualFile) myFixture.configureFromExistingVirtualFile(virtualFile)
val xmlFile = myFixture.elementAtCaret.containingFile as XmlFile
val completionEditor = InjectedLanguageUtil.getEditorForInjectedLanguageNoCommit(myFixture.editor, myFixture.file) myFixture.renameElement(xmlFile, NEW_NAME_XML)
val element = TargetElementUtil.findTargetElement( val expectedImportName = AndroidConst.SYNTHETIC_PACKAGE + ".main." + NEW_NAME
completionEditor, assertTrue((myFixture.file as KtFile).importDirectives.any { it.importedFqName?.asString() == expectedImportName })
TargetElementUtil.REFERENCED_ELEMENT_ACCEPTED or TargetElementUtil.ELEMENT_NAME_ACCEPTED) as XmlAttributeValueImpl
val file = element.containingFile as XmlFile
RenameProcessor(myFixture.project, file, NEW_NAME_XML, false, true).run()
(myFixture.file as KtFile).importDirectives.any { it.importedFqName!!.asString() == AndroidConst.SYNTHETIC_PACKAGE + ".main." + NEW_NAME }
} }
} }