Rename: Fix processing of overriding methods with mangled names
#KT-24460 Fixed
This commit is contained in:
+1
-1
@@ -121,7 +121,7 @@ class RenameKotlinClassifierProcessor : RenameKotlinPsiProcessor() {
|
||||
else -> null
|
||||
}
|
||||
|
||||
override fun renameElement(element: PsiElement, newName: String, usages: Array<out UsageInfo>, listener: RefactoringElementListener?) {
|
||||
override fun renameElement(element: PsiElement, newName: String, usages: Array<UsageInfo>, listener: RefactoringElementListener?) {
|
||||
val simpleUsages = ArrayList<UsageInfo>(usages.size)
|
||||
val ambiguousImportUsages = com.intellij.util.SmartList<UsageInfo>()
|
||||
for (usage in usages) {
|
||||
|
||||
+11
-5
@@ -35,6 +35,8 @@ import org.jetbrains.kotlin.asJava.elements.KtLightElement
|
||||
import org.jetbrains.kotlin.asJava.elements.KtLightMethod
|
||||
import org.jetbrains.kotlin.asJava.namedUnwrappedElement
|
||||
import org.jetbrains.kotlin.asJava.unwrapped
|
||||
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper.InternalNameMapper.demangleInternalName
|
||||
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper.InternalNameMapper.getModuleNameSuffix
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.unsafeResolveToDescriptor
|
||||
import org.jetbrains.kotlin.idea.refactoring.Pass
|
||||
@@ -181,6 +183,8 @@ class RenameKotlinFunctionProcessor : RenameKotlinPsiProcessor() {
|
||||
override fun prepareRenaming(element: PsiElement, newName: String, allRenames: MutableMap<PsiElement, String>, scope: SearchScope) {
|
||||
super.prepareRenaming(element, newName, allRenames, scope)
|
||||
|
||||
val originalName = (element.unwrapped as? KtNamedFunction)?.name ?: ""
|
||||
|
||||
if (element is KtLightMethod && getJvmName(element) == null) {
|
||||
(element.kotlinOrigin as? KtNamedFunction)?.let { allRenames[it] = newName }
|
||||
}
|
||||
@@ -190,22 +194,22 @@ class RenameKotlinFunctionProcessor : RenameKotlinPsiProcessor() {
|
||||
for (declaration in ((element as? FunctionWithSupersWrapper)?.supers ?: listOf(element))) {
|
||||
val psiMethod = wrapPsiMethod(declaration) ?: continue
|
||||
allRenames[declaration] = newName
|
||||
val baseName = psiMethod.name
|
||||
val newBaseName = if (demangleInternalName(baseName) == originalName) "$newName$${getModuleNameSuffix(baseName)}" else newName
|
||||
if (psiMethod.containingClass != null) {
|
||||
psiMethod.forEachOverridingMethod { it ->
|
||||
psiMethod.forEachOverridingMethod(scope) { it ->
|
||||
val overrider = (it as? PsiMirrorElement)?.prototype as? PsiMethod ?: it
|
||||
|
||||
if (overrider is SyntheticElement) return@forEachOverridingMethod true
|
||||
|
||||
val overriderName = overrider.name
|
||||
val baseName = psiMethod.name
|
||||
val newOverriderName = RefactoringUtil.suggestNewOverriderName(overriderName, baseName, newName)
|
||||
val newOverriderName = RefactoringUtil.suggestNewOverriderName(overriderName, baseName, newBaseName)
|
||||
if (newOverriderName != null) {
|
||||
RenameProcessor.assertNonCompileElement(overrider)
|
||||
allRenames.put(overrider, newOverriderName)
|
||||
}
|
||||
return@forEachOverridingMethod true
|
||||
}
|
||||
javaMethodProcessorInstance.prepareRenaming(psiMethod, newName, allRenames, scope)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -223,7 +227,9 @@ class RenameKotlinFunctionProcessor : RenameKotlinPsiProcessor() {
|
||||
ambiguousImportUsages += usage
|
||||
}
|
||||
else {
|
||||
simpleUsages += usage
|
||||
if (!renameUsageIfPossible(usage, element, newName)) {
|
||||
simpleUsages += usage
|
||||
}
|
||||
}
|
||||
}
|
||||
element.ambiguousImportUsages = ambiguousImportUsages
|
||||
|
||||
+1
-1
@@ -53,7 +53,7 @@ class RenameKotlinParameterProcessor : RenameKotlinPsiProcessor() {
|
||||
result += collisions
|
||||
}
|
||||
|
||||
override fun renameElement(element: PsiElement, newName: String, usages: Array<out UsageInfo>, listener: RefactoringElementListener?) {
|
||||
override fun renameElement(element: PsiElement, newName: String, usages: Array<UsageInfo>, listener: RefactoringElementListener?) {
|
||||
super.renameElement(element, newName, usages, listener)
|
||||
|
||||
usages.forEach { (it as? KtResolvableCollisionUsageInfo)?.apply() }
|
||||
|
||||
+19
-6
@@ -36,6 +36,9 @@ import org.jetbrains.kotlin.asJava.*
|
||||
import org.jetbrains.kotlin.asJava.classes.KtLightClass
|
||||
import org.jetbrains.kotlin.asJava.elements.KtLightDeclaration
|
||||
import org.jetbrains.kotlin.asJava.elements.KtLightMethod
|
||||
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper.InternalNameMapper.demangleInternalName
|
||||
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper.InternalNameMapper.getModuleNameSuffix
|
||||
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper.InternalNameMapper.mangleInternalName
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
|
||||
@@ -323,16 +326,21 @@ class RenameKotlinPropertyProcessor : RenameKotlinPsiProcessor() {
|
||||
}
|
||||
|
||||
for (propertyMethod in propertyMethods) {
|
||||
if (element is KtDeclaration && newPropertyName != null) {
|
||||
val mangledPropertyName = if (propertyMethod is KtLightMethod && propertyMethod.isMangled) {
|
||||
val suffix = getModuleNameSuffix(propertyMethod.name)
|
||||
if (suffix != null && newPropertyName != null) mangleInternalName(newPropertyName, suffix) else null
|
||||
} else null
|
||||
val adjustedPropertyName = mangledPropertyName ?: newPropertyName
|
||||
if (element is KtDeclaration && adjustedPropertyName != null) {
|
||||
val wrapper = PropertyMethodWrapper(propertyMethod)
|
||||
when {
|
||||
JvmAbi.isGetterName(propertyMethod.name) && getterJvmName == null ->
|
||||
allRenames[wrapper] = JvmAbi.getterName(newPropertyName)
|
||||
allRenames[wrapper] = JvmAbi.getterName(adjustedPropertyName)
|
||||
JvmAbi.isSetterName(propertyMethod.name) && setterJvmName == null ->
|
||||
allRenames[wrapper] = JvmAbi.setterName(newPropertyName)
|
||||
allRenames[wrapper] = JvmAbi.setterName(adjustedPropertyName)
|
||||
}
|
||||
}
|
||||
addRenameElements(propertyMethod, (element as PsiNamedElement).name, newPropertyName, allRenames, scope)
|
||||
addRenameElements(propertyMethod, (element as PsiNamedElement).name, adjustedPropertyName, allRenames, scope)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -389,7 +397,10 @@ class RenameKotlinPropertyProcessor : RenameKotlinPsiProcessor() {
|
||||
val refKindUsages = adjustedUsages.groupBy { usage: UsageInfo ->
|
||||
val refElement = usage.reference?.resolve()
|
||||
if (refElement is PsiMethod) {
|
||||
when (refElement.name) {
|
||||
val refElementName = refElement.name
|
||||
val refElementNameToCheck =
|
||||
(if (usage is MangledJavaRefUsageInfo) demangleInternalName(refElementName) else null) ?: refElementName
|
||||
when (refElementNameToCheck) {
|
||||
oldGetterName -> UsageKind.GETTER_USAGE
|
||||
oldSetterName -> UsageKind.SETTER_USAGE
|
||||
else -> UsageKind.SIMPLE_PROPERTY_USAGE
|
||||
@@ -441,7 +452,9 @@ class RenameKotlinPropertyProcessor : RenameKotlinPsiProcessor() {
|
||||
}
|
||||
}
|
||||
else {
|
||||
val newOverriderName = RefactoringUtil.suggestNewOverriderName(overriderName, oldName, newName)
|
||||
val demangledName = if (newName != null && overrider is KtLightMethod && overrider.isMangled) demangleInternalName(newName) else null
|
||||
val adjustedName = demangledName ?: newName
|
||||
val newOverriderName = RefactoringUtil.suggestNewOverriderName(overriderName, oldName, adjustedName)
|
||||
if (newOverriderName != null) {
|
||||
allRenames[overriderElement] = newOverriderName
|
||||
}
|
||||
|
||||
@@ -24,10 +24,15 @@ import com.intellij.psi.search.searches.ReferencesSearch
|
||||
import com.intellij.psi.util.PsiUtilCore
|
||||
import com.intellij.refactoring.listeners.RefactoringElementListener
|
||||
import com.intellij.refactoring.rename.RenamePsiElementProcessor
|
||||
import com.intellij.refactoring.rename.RenameUtil
|
||||
import com.intellij.refactoring.util.MoveRenameUsageInfo
|
||||
import com.intellij.usageView.UsageInfo
|
||||
import org.jetbrains.kotlin.asJava.elements.KtLightMethod
|
||||
import org.jetbrains.kotlin.asJava.namedUnwrappedElement
|
||||
import org.jetbrains.kotlin.asJava.toLightMethods
|
||||
import org.jetbrains.kotlin.asJava.unwrapped
|
||||
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper
|
||||
import org.jetbrains.kotlin.idea.references.KtReference
|
||||
import org.jetbrains.kotlin.idea.search.ideaExtensions.KotlinReferencesSearchOptions
|
||||
import org.jetbrains.kotlin.idea.search.ideaExtensions.KotlinReferencesSearchParameters
|
||||
import org.jetbrains.kotlin.idea.search.projectScope
|
||||
@@ -40,15 +45,43 @@ import org.jetbrains.kotlin.psi.psiUtil.isIdentifier
|
||||
import org.jetbrains.kotlin.psi.psiUtil.parents
|
||||
import org.jetbrains.kotlin.psi.psiUtil.quoteIfNeeded
|
||||
import org.jetbrains.kotlin.resolve.ImportPath
|
||||
import java.util.ArrayList
|
||||
import kotlin.collections.Collection
|
||||
import kotlin.collections.HashSet
|
||||
import kotlin.collections.List
|
||||
import kotlin.collections.MutableMap
|
||||
import kotlin.collections.flatMapTo
|
||||
import kotlin.collections.forEach
|
||||
import kotlin.collections.isEmpty
|
||||
import kotlin.collections.mapNotNullTo
|
||||
import kotlin.collections.none
|
||||
import kotlin.collections.plusAssign
|
||||
import kotlin.collections.set
|
||||
import kotlin.collections.toMutableList
|
||||
import kotlin.collections.toTypedArray
|
||||
|
||||
abstract class RenameKotlinPsiProcessor : RenamePsiElementProcessor() {
|
||||
class MangledJavaRefUsageInfo(
|
||||
val manglingSuffix: String,
|
||||
element: PsiElement,
|
||||
ref: PsiReference,
|
||||
referenceElement: PsiElement
|
||||
) : MoveRenameUsageInfo(
|
||||
referenceElement,
|
||||
ref,
|
||||
ref.getRangeInElement().getStartOffset(),
|
||||
ref.getRangeInElement().getEndOffset(),
|
||||
element,
|
||||
false
|
||||
)
|
||||
|
||||
override fun canProcessElement(element: PsiElement): Boolean = element is KtNamedDeclaration
|
||||
|
||||
override fun findReferences(element: PsiElement): Collection<PsiReference> {
|
||||
val searchParameters = KotlinReferencesSearchParameters(
|
||||
element,
|
||||
element.project.projectScope(),
|
||||
kotlinOptions = KotlinReferencesSearchOptions(searchForComponentConventions = false)
|
||||
element,
|
||||
element.project.projectScope(),
|
||||
kotlinOptions = KotlinReferencesSearchOptions(searchForComponentConventions = false)
|
||||
)
|
||||
val references = ReferencesSearch.search(searchParameters).toMutableList()
|
||||
if (element is KtNamedFunction
|
||||
@@ -59,6 +92,23 @@ abstract class RenameKotlinPsiProcessor : RenamePsiElementProcessor() {
|
||||
return references
|
||||
}
|
||||
|
||||
override fun createUsageInfo(element: PsiElement, ref: PsiReference, referenceElement: PsiElement): UsageInfo {
|
||||
if (ref !is KtReference) {
|
||||
val targetElement = ref.resolve()
|
||||
if (targetElement is KtLightMethod && targetElement.isMangled) {
|
||||
KotlinTypeMapper.InternalNameMapper.getModuleNameSuffix(targetElement.name)?.let {
|
||||
return MangledJavaRefUsageInfo(
|
||||
it,
|
||||
element,
|
||||
ref,
|
||||
referenceElement
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
return super.createUsageInfo(element, ref, referenceElement)
|
||||
}
|
||||
|
||||
override fun getElementToSearchInStringsAndComments(element: PsiElement): PsiElement? {
|
||||
val unwrapped = element?.unwrapped ?: return null
|
||||
if ((unwrapped is KtDeclaration) && KtPsiUtil.isLocal(unwrapped as KtDeclaration)) return null
|
||||
@@ -101,12 +151,44 @@ abstract class RenameKotlinPsiProcessor : RenamePsiElementProcessor() {
|
||||
&& ref.multiResolve(false).mapNotNullTo(HashSet()) { it.element?.unwrapped }.size > 1
|
||||
}
|
||||
|
||||
protected fun renameUsageIfPossible(usage: UsageInfo, element: PsiElement, newName: String): Boolean {
|
||||
var chosenName: String? = null
|
||||
if (usage is MangledJavaRefUsageInfo) {
|
||||
chosenName = KotlinTypeMapper.InternalNameMapper.mangleInternalName(newName, usage.manglingSuffix)
|
||||
} else {
|
||||
val reference = usage.reference
|
||||
if (reference is KtReference) {
|
||||
chosenName = (if (element is KtLightMethod && element.isMangled) KotlinTypeMapper.InternalNameMapper.demangleInternalName(newName) else null) ?: newName
|
||||
}
|
||||
}
|
||||
if (chosenName == null) return false
|
||||
usage.reference?.handleElementRename(chosenName)
|
||||
return true
|
||||
}
|
||||
|
||||
override fun renameElement(
|
||||
element: PsiElement,
|
||||
newName: String,
|
||||
usages: Array<UsageInfo>,
|
||||
listener: RefactoringElementListener?
|
||||
) {
|
||||
val simpleUsages = ArrayList<UsageInfo>(usages.size)
|
||||
for (usage in usages) {
|
||||
if (renameUsageIfPossible(usage, element, newName)) continue
|
||||
simpleUsages += usage
|
||||
}
|
||||
|
||||
RenameUtil.doRenameGenericNamedElement(element, newName, simpleUsages.toTypedArray(), listener)
|
||||
}
|
||||
|
||||
override fun getPostRenameCallback(element: PsiElement, newName: String, elementListener: RefactoringElementListener): Runnable? {
|
||||
return Runnable {
|
||||
element.ambiguousImportUsages?.forEach {
|
||||
val ref = it.reference as? PsiPolyVariantReference ?: return@forEach
|
||||
if (ref.multiResolve(false).isEmpty()) {
|
||||
ref.handleElementRename(newName)
|
||||
if (!renameUsageIfPossible(it, element, newName)) {
|
||||
ref.handleElementRename(newName)
|
||||
}
|
||||
}
|
||||
else {
|
||||
ref.element?.getStrictParentOfType<KtImportDirective>()?.let { importDirective ->
|
||||
|
||||
+23
@@ -24,6 +24,7 @@ import com.intellij.psi.search.UsageSearchContext
|
||||
import com.intellij.psi.search.searches.MethodReferencesSearch
|
||||
import com.intellij.psi.util.MethodSignatureUtil
|
||||
import com.intellij.psi.util.TypeConversionUtil
|
||||
import org.jetbrains.kotlin.asJava.elements.KtLightMethod
|
||||
import org.jetbrains.kotlin.asJava.toLightMethods
|
||||
import org.jetbrains.kotlin.compatibility.ExecutorProcessor
|
||||
import org.jetbrains.kotlin.idea.references.KtSimpleNameReference
|
||||
@@ -31,8 +32,10 @@ import org.jetbrains.kotlin.idea.references.SyntheticPropertyAccessorReference
|
||||
import org.jetbrains.kotlin.idea.references.readWriteAccess
|
||||
import org.jetbrains.kotlin.idea.search.restrictToKotlinSources
|
||||
import org.jetbrains.kotlin.idea.util.runReadActionInSmartMode
|
||||
import org.jetbrains.kotlin.lexer.KtTokens
|
||||
import org.jetbrains.kotlin.load.java.JvmAbi
|
||||
import org.jetbrains.kotlin.load.java.getPropertyNamesCandidatesByAccessorName
|
||||
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper.InternalNameMapper.demangleInternalName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.psi.KtCallableDeclaration
|
||||
import org.jetbrains.kotlin.psi.KtNamedFunction
|
||||
@@ -47,6 +50,26 @@ class KotlinOverridingMethodReferenceSearcher : MethodUsagesSearcher() {
|
||||
return
|
||||
}
|
||||
|
||||
if (method is KtLightMethod) {
|
||||
method.kotlinOrigin?.let { ktElement ->
|
||||
val (mayBeMangled, name) = p.project.runReadActionInSmartMode {
|
||||
ktElement.hasModifier(KtTokens.PRIVATE_KEYWORD) || ktElement.hasModifier(KtTokens.INTERNAL_KEYWORD)
|
||||
} to method.name
|
||||
if (mayBeMangled && name != null) {
|
||||
val demangledName = demangleInternalName(name)
|
||||
if (demangledName != null) {
|
||||
val wrappedMethod = object : KtLightMethod by method {
|
||||
override fun getName(): String = demangledName
|
||||
}
|
||||
processQuery(
|
||||
MethodReferencesSearch.SearchParameters(wrappedMethod, p.scopeDeterminedByUser, p.isStrictSignatureSearch, p.optimizer),
|
||||
consumer
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val searchScope = p.project.runReadActionInSmartMode {
|
||||
p.effectiveSearchScope
|
||||
.intersectWith(method.useScope)
|
||||
|
||||
Reference in New Issue
Block a user