Android Extensions: handle layout file rename
This commit is contained in:
+23
-5
@@ -20,22 +20,40 @@ import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.xml.XmlAttributeValue
|
||||
import org.jetbrains.android.dom.wrappers.ValueResourceElementWrapper
|
||||
import org.jetbrains.android.util.AndroidResourceUtil
|
||||
import org.jetbrains.kotlin.android.synthetic.AndroidConst
|
||||
import org.jetbrains.kotlin.android.synthetic.androidIdToName
|
||||
import org.jetbrains.kotlin.idea.references.KtSimpleNameReference
|
||||
import org.jetbrains.kotlin.plugin.references.SimpleNameReferenceExtension
|
||||
import org.jetbrains.kotlin.psi.KtDotQualifiedExpression
|
||||
import org.jetbrains.kotlin.psi.KtPsiFactory
|
||||
|
||||
class AndroidSimpleNameReferenceExtension : SimpleNameReferenceExtension {
|
||||
|
||||
override fun isReferenceTo(reference: KtSimpleNameReference, element: PsiElement): Boolean {
|
||||
return element is ValueResourceElementWrapper && AndroidResourceUtil.isIdDeclaration(element)
|
||||
override fun isReferenceTo(reference: KtSimpleNameReference, element: PsiElement) = when {
|
||||
element is ValueResourceElementWrapper && AndroidResourceUtil.isIdDeclaration(element) -> true
|
||||
isLayoutPackageIdentifier(reference) -> true
|
||||
else -> false
|
||||
}
|
||||
|
||||
private fun isLayoutPackageIdentifier(reference: KtSimpleNameReference): Boolean {
|
||||
val probablyVariant = reference.element?.parent as? KtDotQualifiedExpression ?: return false
|
||||
val probablyKAS = probablyVariant.receiverExpression as? KtDotQualifiedExpression ?: return false
|
||||
return probablyKAS.receiverExpression.text == AndroidConst.SYNTHETIC_PACKAGE
|
||||
}
|
||||
|
||||
override fun handleElementRename(reference: KtSimpleNameReference, psiFactory: KtPsiFactory, newElementName: String): PsiElement? {
|
||||
val resolvedElement = reference.resolve()
|
||||
if (resolvedElement !is XmlAttributeValue || !AndroidResourceUtil.isIdDeclaration(resolvedElement)) return null
|
||||
val newSyntheticPropertyName = androidIdToName(newElementName) ?: return null
|
||||
if (resolvedElement is XmlAttributeValue && AndroidResourceUtil.isIdDeclaration(resolvedElement)) {
|
||||
val newSyntheticPropertyName = androidIdToName(newElementName) ?: return null
|
||||
return psiFactory.createNameIdentifier(newSyntheticPropertyName.name)
|
||||
}
|
||||
else if (isLayoutPackageIdentifier(reference)) {
|
||||
return if (newElementName.endsWith(".xml"))
|
||||
psiFactory.createSimpleName(newElementName.dropLast(".xml".length))
|
||||
else
|
||||
reference.element
|
||||
}
|
||||
|
||||
return psiFactory.createNameIdentifier(newSyntheticPropertyName.name)
|
||||
return null
|
||||
}
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<Button
|
||||
android:id="@+id/login"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
</FrameLayout>
|
||||
Vendored
+12
@@ -0,0 +1,12 @@
|
||||
package com.myapp
|
||||
|
||||
import android.app.Activity
|
||||
import android.os.Bundle
|
||||
import java.io.File
|
||||
import kotlinx.android.synthetic.main.layout.*
|
||||
|
||||
class MyActivity : Activity() {
|
||||
override fun onCreate(savedInstanceState: Bundle?) {}
|
||||
val button = <caret>login
|
||||
}
|
||||
|
||||
+51
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright 2010-2016 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
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 org.jetbrains.kotlin.android.synthetic.AndroidConst
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
|
||||
abstract class AbstractAndroidLayoutRenameTest : KotlinAndroidTestCase() {
|
||||
private val NEW_NAME = "new_name"
|
||||
private val NEW_NAME_XML = "$NEW_NAME.xml"
|
||||
|
||||
fun doTest(path: String) {
|
||||
val f = myFixture!!
|
||||
getResourceDirs(path).forEach { myFixture.copyDirectoryToProject(it.name, it.name) }
|
||||
val virtualFile = f.copyFileToProject(path + getTestName(true) + ".kt", "src/" + getTestName(true) + ".kt");
|
||||
f.configureFromExistingVirtualFile(virtualFile)
|
||||
|
||||
val completionEditor = InjectedLanguageUtil.getEditorForInjectedLanguageNoCommit(f.editor, f.file)
|
||||
|
||||
val element = TargetElementUtil.findTargetElement(
|
||||
completionEditor,
|
||||
TargetElementUtil.REFERENCED_ELEMENT_ACCEPTED or TargetElementUtil.ELEMENT_NAME_ACCEPTED) as XmlAttributeValueImpl
|
||||
|
||||
val file = element.containingFile as XmlFile
|
||||
|
||||
RenameProcessor(f.project, file, NEW_NAME_XML, false, true).run()
|
||||
|
||||
(f.file as KtFile).importDirectives.any { it.importedFqName!!.asString() == AndroidConst.SYNTHETIC_PACKAGE + ".main." + NEW_NAME }
|
||||
}
|
||||
|
||||
override fun getTestDataPath() = KotlinAndroidTestCaseBase.getPluginTestDataPathBase() + "/rename/" + getTestName(true) + "/"
|
||||
}
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright 2010-2015 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.android;
|
||||
|
||||
import com.intellij.testFramework.TestDataPath;
|
||||
import org.jetbrains.kotlin.test.JUnit3RunnerWithInners;
|
||||
import org.jetbrains.kotlin.test.KotlinTestUtils;
|
||||
import org.jetbrains.kotlin.test.TestMetadata;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/** This class is generated by {@link org.jetbrains.kotlin.generators.tests.TestsPackage}. DO NOT MODIFY MANUALLY */
|
||||
@SuppressWarnings("all")
|
||||
@TestMetadata("plugins/android-extensions/android-extensions-idea/testData/android/renameLayout")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public class AndroidLayoutRenameTestGenerated extends AbstractAndroidLayoutRenameTest {
|
||||
public void testAllFilesPresentInRenameLayout() throws Exception {
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("plugins/android-extensions/android-extensions-idea/testData/android/renameLayout"), Pattern.compile("^([^\\.]+)$"), false);
|
||||
}
|
||||
|
||||
@TestMetadata("simple")
|
||||
public void testSimple() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("plugins/android-extensions/android-extensions-idea/testData/android/renameLayout/simple/");
|
||||
doTest(fileName);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user