Android Extensions: handle layout file rename
This commit is contained in:
@@ -223,6 +223,7 @@ Issues fixed:
|
|||||||
- [KT-11264](https://youtrack.jetbrains.com/issue/KT-11264) Action to create new activity in Kotlin
|
- [KT-11264](https://youtrack.jetbrains.com/issue/KT-11264) Action to create new activity in Kotlin
|
||||||
- [KT-11201](https://youtrack.jetbrains.com/issue/KT-11201) Do not ignore items with similar names in kapt
|
- [KT-11201](https://youtrack.jetbrains.com/issue/KT-11201) Do not ignore items with similar names in kapt
|
||||||
- [KT-7729](https://youtrack.jetbrains.com/issue/KT-7729) Add Android Lint checks for Kotlin (Android Studio 1.5)
|
- [KT-7729](https://youtrack.jetbrains.com/issue/KT-7729) Add Android Lint checks for Kotlin (Android Studio 1.5)
|
||||||
|
- Rename Android Extensions imports when the layout file is renamed
|
||||||
|
|
||||||
### Maven
|
### Maven
|
||||||
|
|
||||||
|
|||||||
@@ -998,6 +998,10 @@ fun main(args: Array<String>) {
|
|||||||
model("android/rename", recursive = false, extension = null)
|
model("android/rename", recursive = false, extension = null)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
testClass<AbstractAndroidLayoutRenameTest>() {
|
||||||
|
model("android/renameLayout", recursive = false, extension = null)
|
||||||
|
}
|
||||||
|
|
||||||
testClass<AbstractAndroidFindUsagesTest>() {
|
testClass<AbstractAndroidFindUsagesTest>() {
|
||||||
model("android/findUsages", recursive = false, extension = null)
|
model("android/findUsages", recursive = false, extension = null)
|
||||||
}
|
}
|
||||||
|
|||||||
+23
-5
@@ -20,22 +20,40 @@ 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 org.jetbrains.android.dom.wrappers.ValueResourceElementWrapper
|
||||||
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.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.KtPsiFactory
|
import org.jetbrains.kotlin.psi.KtPsiFactory
|
||||||
|
|
||||||
class AndroidSimpleNameReferenceExtension : SimpleNameReferenceExtension {
|
class AndroidSimpleNameReferenceExtension : SimpleNameReferenceExtension {
|
||||||
|
|
||||||
override fun isReferenceTo(reference: KtSimpleNameReference, element: PsiElement): Boolean {
|
override fun isReferenceTo(reference: KtSimpleNameReference, element: PsiElement) = when {
|
||||||
return element is ValueResourceElementWrapper && AndroidResourceUtil.isIdDeclaration(element)
|
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? {
|
override fun handleElementRename(reference: KtSimpleNameReference, psiFactory: KtPsiFactory, newElementName: String): PsiElement? {
|
||||||
val resolvedElement = reference.resolve()
|
val resolvedElement = reference.resolve()
|
||||||
if (resolvedElement !is XmlAttributeValue || !AndroidResourceUtil.isIdDeclaration(resolvedElement)) return null
|
if (resolvedElement is XmlAttributeValue && AndroidResourceUtil.isIdDeclaration(resolvedElement)) {
|
||||||
val newSyntheticPropertyName = androidIdToName(newElementName) ?: return null
|
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