#KT-25674: Fix unexpected reference renames in literals when moving referenced files.

This commit is contained in:
Vadim Brilyantov
2019-02-18 14:55:55 +03:00
parent c7acd89fad
commit c633f7568f
2 changed files with 49 additions and 20 deletions
@@ -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<PsiReference>()
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
}
}
@@ -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<out PsiReference> {
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<out Any> {
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<out Any> {
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
)
}
}