From c633f7568f8b4aabd459e8e8b7adffd8b3a76a84 Mon Sep 17 00:00:00 2001 From: Vadim Brilyantov Date: Mon, 18 Feb 2019 14:55:55 +0300 Subject: [PATCH] #KT-25674: Fix unexpected reference renames in literals when moving referenced files. --- .../MoveKotlinDeclarationsProcessor.kt | 18 ++++++- .../KotlinFilePathReferenceContributor.kt | 51 ++++++++++++------- 2 files changed, 49 insertions(+), 20 deletions(-) diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/move/moveDeclarations/MoveKotlinDeclarationsProcessor.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/move/moveDeclarations/MoveKotlinDeclarationsProcessor.kt index 87866606a63..e8f7a4362dd 100644 --- a/idea/src/org/jetbrains/kotlin/idea/refactoring/move/moveDeclarations/MoveKotlinDeclarationsProcessor.kt +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/move/moveDeclarations/MoveKotlinDeclarationsProcessor.kt @@ -64,7 +64,6 @@ import org.jetbrains.kotlin.psi.psiUtil.getElementTextWithContext import org.jetbrains.kotlin.psi.psiUtil.isAncestor import org.jetbrains.kotlin.utils.ifEmpty import org.jetbrains.kotlin.utils.keysToMap -import java.lang.AssertionError import java.util.* interface Mover : (KtNamedDeclaration, KtElement) -> KtNamedDeclaration { @@ -205,6 +204,10 @@ class MoveKotlinDeclarationsProcessor( val searchScope = getSearchScope(lightElement) ?: return@flatMapTo emptyList() val newFqName = StringUtil.getQualifiedName(newContainerName, lightElement.name) + val newFqNameForKt = StringUtil.getQualifiedName( + newContainerName, + lightElement.namedUnwrappedElement?.name?: lightElement.name + ) val foundReferences = HashSet() val results = ReferencesSearch @@ -232,6 +235,19 @@ class MoveKotlinDeclarationsProcessor( if (handler !is MoveKotlinClassHandler) handler.preprocessUsages(results) } + results + .filter { it is NonCodeUsageInfo && it.file is KtFile } + .forEach { + val newText = NonCodeUsageInfo::class.java.getField("newText") + // A 'newText' is marked as final initially, but here we need to change it to prevent + // light-class names in kotlin files. + val oldAccessibility = newText.isAccessible + newText.isAccessible = true + newText.set(it, newFqNameForKt) + // Restore initial accessibility of 'newText' field. + newText.isAccessible = oldAccessibility + } + results } } diff --git a/idea/src/org/jetbrains/kotlin/idea/references/KotlinFilePathReferenceContributor.kt b/idea/src/org/jetbrains/kotlin/idea/references/KotlinFilePathReferenceContributor.kt index d344bd857a3..406f2987a72 100644 --- a/idea/src/org/jetbrains/kotlin/idea/references/KotlinFilePathReferenceContributor.kt +++ b/idea/src/org/jetbrains/kotlin/idea/references/KotlinFilePathReferenceContributor.kt @@ -24,42 +24,55 @@ import com.intellij.psi.PsiReferenceRegistrar import com.intellij.psi.impl.source.resolve.reference.impl.providers.FilePathReferenceProvider import com.intellij.psi.impl.source.resolve.reference.impl.providers.FileReference import com.intellij.util.ProcessingContext +import org.jetbrains.kotlin.idea.completion.KotlinCompletionCharFilter import org.jetbrains.kotlin.psi.KtStringTemplateExpression import org.jetbrains.kotlin.psi.psiUtil.getContentRange import org.jetbrains.kotlin.psi.psiUtil.isPlain import org.jetbrains.kotlin.psi.psiUtil.plainContent -import org.jetbrains.kotlin.idea.completion.KotlinCompletionCharFilter class KotlinFilePathReferenceContributor : AbstractKotlinReferenceContributor() { object KotlinFilePathReferenceProvider : FilePathReferenceProvider() { override fun getReferencesByElement(element: PsiElement, context: ProcessingContext): Array { if (element !is KtStringTemplateExpression) return PsiReference.EMPTY_ARRAY if (!element.isPlain()) return PsiReference.EMPTY_ARRAY - return getReferencesByElement(element, element.plainContent, element.getContentRange().startOffset, true) - .map { - if (it is FileReference) { - object: FileReference(it.fileReferenceSet, it.rangeInElement, it.index, it.text) { - override fun getVariants(): Array { - return super.getVariants() - .map { - (it as? LookupElement)?.apply { - putUserData(KotlinCompletionCharFilter.SUPPRESS_ITEM_SELECTION_BY_CHARS_ON_TYPING, Unit) - } ?: it - } - .toTypedArray() - } + val refByElem = getReferencesByElement(element, element.plainContent, element.getContentRange().startOffset, true) + val res = refByElem + .map { + if (it is FileReference) { + object : FileReference(it.fileReferenceSet, it.rangeInElement, it.index, it.text) { + override fun getVariants(): Array { + return super.getVariants() + .map { + (it as? LookupElement)?.apply { + putUserData(KotlinCompletionCharFilter.SUPPRESS_ITEM_SELECTION_BY_CHARS_ON_TYPING, Unit) + } ?: it + } + .toTypedArray() + } + + // Note: this is a hack that prevents IDE from renaming paths in string literals when doing move. + // TODO: find another way of doing this (that may need re-implementing move files refactoring using .java move) + override fun getLastFileReference() = null + + override fun bindToElement(element: PsiElement): PsiElement { + return rename(element.text) + } + + override fun bindToElement(element: PsiElement, absolute: Boolean): PsiElement { + return rename(element.text) } } - else it - } - .toTypedArray() + } else it + } + .toTypedArray() + return res } } override fun registerReferenceProviders(registrar: PsiReferenceRegistrar) { registrar.registerReferenceProvider( - PlatformPatterns.psiElement(KtStringTemplateExpression::class.java), - KotlinFilePathReferenceProvider + PlatformPatterns.psiElement(KtStringTemplateExpression::class.java), + KotlinFilePathReferenceProvider ) } }