Rename: Fix processing of overriding methods with mangled names

#KT-24460 Fixed
This commit is contained in:
Alexey Sedunov
2018-05-30 13:47:40 +03:00
parent eea9113d1c
commit 862dc76ed9
21 changed files with 320 additions and 25 deletions
@@ -1676,13 +1676,21 @@ public class KotlinTypeMapper {
} }
@Nullable @Nullable
public static String internalNameWithoutModuleSuffix(@NotNull String name) { public static String demangleInternalName(@NotNull String name) {
int indexOfDollar = name.indexOf('$'); int indexOfDollar = name.indexOf('$');
if (indexOfDollar == -1) { return indexOfDollar >= 0 ? name.substring(0, indexOfDollar) : null;
return null; }
}
return name.substring(0, indexOfDollar) + '$'; @Nullable
public static String getModuleNameSuffix(@NotNull String name) {
int indexOfDollar = name.indexOf('$');
return indexOfDollar >=0 ? name.substring(indexOfDollar + 1) : null;
}
@Nullable
public static String internalNameWithoutModuleSuffix(@NotNull String name) {
String demangledName = demangleInternalName(name);
return demangledName != null ? demangledName + '$' : null;
} }
} }
} }
@@ -44,4 +44,6 @@ interface KtLightMethod : PsiAnnotationMethod, KtLightMember<PsiMethod> {
val isDelegated: Boolean val isDelegated: Boolean
get() = lightMemberOrigin?.originKind == JvmDeclarationOriginKind.DELEGATION get() = lightMemberOrigin?.originKind == JvmDeclarationOriginKind.DELEGATION
|| lightMemberOrigin?.originKind == JvmDeclarationOriginKind.CLASS_MEMBER_DELEGATION_TO_DEFAULT_IMPL || lightMemberOrigin?.originKind == JvmDeclarationOriginKind.CLASS_MEMBER_DELEGATION_TO_DEFAULT_IMPL
val isMangled: Boolean
} }
@@ -30,6 +30,7 @@ import org.jetbrains.kotlin.asJava.classes.cannotModify
import org.jetbrains.kotlin.asJava.classes.lazyPub import org.jetbrains.kotlin.asJava.classes.lazyPub
import org.jetbrains.kotlin.asJava.propertyNameByAccessor import org.jetbrains.kotlin.asJava.propertyNameByAccessor
import org.jetbrains.kotlin.asJava.unwrapped import org.jetbrains.kotlin.asJava.unwrapped
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper
import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.resolve.DescriptorUtils
@@ -84,9 +85,17 @@ class KtLightMethodImpl private constructor(
} }
} }
override val isMangled: Boolean
get() {
val demangledName = KotlinTypeMapper.InternalNameMapper.demangleInternalName(name) ?: return false
val originalName = propertyNameByAccessor(demangledName, this) ?: demangledName
return originalName == kotlinOrigin?.name
}
override fun setName(name: String): PsiElement? { override fun setName(name: String): PsiElement? {
val jvmNameAnnotation = modifierList.findAnnotation(DescriptorUtils.JVM_NAME.asString()) val jvmNameAnnotation = modifierList.findAnnotation(DescriptorUtils.JVM_NAME.asString())
val newNameForOrigin = propertyNameByAccessor(name, this) ?: name val demangledName = (if (isMangled) KotlinTypeMapper.InternalNameMapper.demangleInternalName(name) else null) ?: name
val newNameForOrigin = propertyNameByAccessor(demangledName, this) ?: demangledName
if (newNameForOrigin == kotlinOrigin?.name) { if (newNameForOrigin == kotlinOrigin?.name) {
jvmNameAnnotation?.delete() jvmNameAnnotation?.delete()
return this return this
@@ -227,6 +227,9 @@ class KotlinReferencesSearcher : QueryExecutorBase<PsiReference, ReferencesSearc
} }
else if (declaration is KtFunction) { else if (declaration is KtFunction) {
processStaticsFromCompanionObject(declaration) processStaticsFromCompanionObject(declaration)
if (element.isMangled) {
searchNamedElement(declaration) { it.restrictToKotlinSources() }
}
} }
} }
@@ -297,9 +300,14 @@ class KotlinReferencesSearcher : QueryExecutorBase<PsiReference, ReferencesSearc
return allMethods.filter { it is KtLightMethod && it.kotlinOrigin == declaration } return allMethods.filter { it is KtLightMethod && it.kotlinOrigin == declaration }
} }
private fun searchNamedElement(element: PsiNamedElement?, name: String? = element?.name) { private fun searchNamedElement(
element: PsiNamedElement?,
name: String? = element?.name,
modifyScope: ((SearchScope) -> SearchScope)? = null
) {
if (name != null && element != null) { if (name != null && element != null) {
val scope = queryParameters.effectiveSearchScope(element) val baseScope = queryParameters.effectiveSearchScope(element)
val scope = if (modifyScope != null) modifyScope(baseScope) else baseScope
val context = UsageSearchContext.IN_CODE + UsageSearchContext.IN_FOREIGN_LANGUAGES + UsageSearchContext.IN_COMMENTS val context = UsageSearchContext.IN_CODE + UsageSearchContext.IN_FOREIGN_LANGUAGES + UsageSearchContext.IN_COMMENTS
val resultProcessor = KotlinRequestResultProcessor(element, val resultProcessor = KotlinRequestResultProcessor(element,
queryParameters.elementToSearch.namedUnwrappedElement ?: element, queryParameters.elementToSearch.namedUnwrappedElement ?: element,
@@ -121,7 +121,7 @@ class RenameKotlinClassifierProcessor : RenameKotlinPsiProcessor() {
else -> null 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 simpleUsages = ArrayList<UsageInfo>(usages.size)
val ambiguousImportUsages = com.intellij.util.SmartList<UsageInfo>() val ambiguousImportUsages = com.intellij.util.SmartList<UsageInfo>()
for (usage in usages) { for (usage in usages) {
@@ -35,6 +35,8 @@ import org.jetbrains.kotlin.asJava.elements.KtLightElement
import org.jetbrains.kotlin.asJava.elements.KtLightMethod import org.jetbrains.kotlin.asJava.elements.KtLightMethod
import org.jetbrains.kotlin.asJava.namedUnwrappedElement import org.jetbrains.kotlin.asJava.namedUnwrappedElement
import org.jetbrains.kotlin.asJava.unwrapped 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.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.idea.caches.resolve.unsafeResolveToDescriptor import org.jetbrains.kotlin.idea.caches.resolve.unsafeResolveToDescriptor
import org.jetbrains.kotlin.idea.refactoring.Pass 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) { override fun prepareRenaming(element: PsiElement, newName: String, allRenames: MutableMap<PsiElement, String>, scope: SearchScope) {
super.prepareRenaming(element, newName, allRenames, scope) super.prepareRenaming(element, newName, allRenames, scope)
val originalName = (element.unwrapped as? KtNamedFunction)?.name ?: ""
if (element is KtLightMethod && getJvmName(element) == null) { if (element is KtLightMethod && getJvmName(element) == null) {
(element.kotlinOrigin as? KtNamedFunction)?.let { allRenames[it] = newName } (element.kotlinOrigin as? KtNamedFunction)?.let { allRenames[it] = newName }
} }
@@ -190,22 +194,22 @@ class RenameKotlinFunctionProcessor : RenameKotlinPsiProcessor() {
for (declaration in ((element as? FunctionWithSupersWrapper)?.supers ?: listOf(element))) { for (declaration in ((element as? FunctionWithSupersWrapper)?.supers ?: listOf(element))) {
val psiMethod = wrapPsiMethod(declaration) ?: continue val psiMethod = wrapPsiMethod(declaration) ?: continue
allRenames[declaration] = newName allRenames[declaration] = newName
val baseName = psiMethod.name
val newBaseName = if (demangleInternalName(baseName) == originalName) "$newName$${getModuleNameSuffix(baseName)}" else newName
if (psiMethod.containingClass != null) { if (psiMethod.containingClass != null) {
psiMethod.forEachOverridingMethod { it -> psiMethod.forEachOverridingMethod(scope) { it ->
val overrider = (it as? PsiMirrorElement)?.prototype as? PsiMethod ?: it val overrider = (it as? PsiMirrorElement)?.prototype as? PsiMethod ?: it
if (overrider is SyntheticElement) return@forEachOverridingMethod true if (overrider is SyntheticElement) return@forEachOverridingMethod true
val overriderName = overrider.name val overriderName = overrider.name
val baseName = psiMethod.name val newOverriderName = RefactoringUtil.suggestNewOverriderName(overriderName, baseName, newBaseName)
val newOverriderName = RefactoringUtil.suggestNewOverriderName(overriderName, baseName, newName)
if (newOverriderName != null) { if (newOverriderName != null) {
RenameProcessor.assertNonCompileElement(overrider) RenameProcessor.assertNonCompileElement(overrider)
allRenames.put(overrider, newOverriderName) allRenames.put(overrider, newOverriderName)
} }
return@forEachOverridingMethod true return@forEachOverridingMethod true
} }
javaMethodProcessorInstance.prepareRenaming(psiMethod, newName, allRenames, scope)
} }
} }
} }
@@ -223,7 +227,9 @@ class RenameKotlinFunctionProcessor : RenameKotlinPsiProcessor() {
ambiguousImportUsages += usage ambiguousImportUsages += usage
} }
else { else {
simpleUsages += usage if (!renameUsageIfPossible(usage, element, newName)) {
simpleUsages += usage
}
} }
} }
element.ambiguousImportUsages = ambiguousImportUsages element.ambiguousImportUsages = ambiguousImportUsages
@@ -53,7 +53,7 @@ class RenameKotlinParameterProcessor : RenameKotlinPsiProcessor() {
result += collisions 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) super.renameElement(element, newName, usages, listener)
usages.forEach { (it as? KtResolvableCollisionUsageInfo)?.apply() } usages.forEach { (it as? KtResolvableCollisionUsageInfo)?.apply() }
@@ -36,6 +36,9 @@ import org.jetbrains.kotlin.asJava.*
import org.jetbrains.kotlin.asJava.classes.KtLightClass import org.jetbrains.kotlin.asJava.classes.KtLightClass
import org.jetbrains.kotlin.asJava.elements.KtLightDeclaration import org.jetbrains.kotlin.asJava.elements.KtLightDeclaration
import org.jetbrains.kotlin.asJava.elements.KtLightMethod 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.ClassDescriptor
import org.jetbrains.kotlin.descriptors.PropertyDescriptor import org.jetbrains.kotlin.descriptors.PropertyDescriptor
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
@@ -323,16 +326,21 @@ class RenameKotlinPropertyProcessor : RenameKotlinPsiProcessor() {
} }
for (propertyMethod in propertyMethods) { 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) val wrapper = PropertyMethodWrapper(propertyMethod)
when { when {
JvmAbi.isGetterName(propertyMethod.name) && getterJvmName == null -> JvmAbi.isGetterName(propertyMethod.name) && getterJvmName == null ->
allRenames[wrapper] = JvmAbi.getterName(newPropertyName) allRenames[wrapper] = JvmAbi.getterName(adjustedPropertyName)
JvmAbi.isSetterName(propertyMethod.name) && setterJvmName == null -> 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 refKindUsages = adjustedUsages.groupBy { usage: UsageInfo ->
val refElement = usage.reference?.resolve() val refElement = usage.reference?.resolve()
if (refElement is PsiMethod) { 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 oldGetterName -> UsageKind.GETTER_USAGE
oldSetterName -> UsageKind.SETTER_USAGE oldSetterName -> UsageKind.SETTER_USAGE
else -> UsageKind.SIMPLE_PROPERTY_USAGE else -> UsageKind.SIMPLE_PROPERTY_USAGE
@@ -441,7 +452,9 @@ class RenameKotlinPropertyProcessor : RenameKotlinPsiProcessor() {
} }
} }
else { 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) { if (newOverriderName != null) {
allRenames[overriderElement] = newOverriderName allRenames[overriderElement] = newOverriderName
} }
@@ -24,10 +24,15 @@ import com.intellij.psi.search.searches.ReferencesSearch
import com.intellij.psi.util.PsiUtilCore import com.intellij.psi.util.PsiUtilCore
import com.intellij.refactoring.listeners.RefactoringElementListener import com.intellij.refactoring.listeners.RefactoringElementListener
import com.intellij.refactoring.rename.RenamePsiElementProcessor import com.intellij.refactoring.rename.RenamePsiElementProcessor
import com.intellij.refactoring.rename.RenameUtil
import com.intellij.refactoring.util.MoveRenameUsageInfo
import com.intellij.usageView.UsageInfo import com.intellij.usageView.UsageInfo
import org.jetbrains.kotlin.asJava.elements.KtLightMethod
import org.jetbrains.kotlin.asJava.namedUnwrappedElement import org.jetbrains.kotlin.asJava.namedUnwrappedElement
import org.jetbrains.kotlin.asJava.toLightMethods import org.jetbrains.kotlin.asJava.toLightMethods
import org.jetbrains.kotlin.asJava.unwrapped 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.KotlinReferencesSearchOptions
import org.jetbrains.kotlin.idea.search.ideaExtensions.KotlinReferencesSearchParameters import org.jetbrains.kotlin.idea.search.ideaExtensions.KotlinReferencesSearchParameters
import org.jetbrains.kotlin.idea.search.projectScope 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.parents
import org.jetbrains.kotlin.psi.psiUtil.quoteIfNeeded import org.jetbrains.kotlin.psi.psiUtil.quoteIfNeeded
import org.jetbrains.kotlin.resolve.ImportPath 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() { 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 canProcessElement(element: PsiElement): Boolean = element is KtNamedDeclaration
override fun findReferences(element: PsiElement): Collection<PsiReference> { override fun findReferences(element: PsiElement): Collection<PsiReference> {
val searchParameters = KotlinReferencesSearchParameters( val searchParameters = KotlinReferencesSearchParameters(
element, element,
element.project.projectScope(), element.project.projectScope(),
kotlinOptions = KotlinReferencesSearchOptions(searchForComponentConventions = false) kotlinOptions = KotlinReferencesSearchOptions(searchForComponentConventions = false)
) )
val references = ReferencesSearch.search(searchParameters).toMutableList() val references = ReferencesSearch.search(searchParameters).toMutableList()
if (element is KtNamedFunction if (element is KtNamedFunction
@@ -59,6 +92,23 @@ abstract class RenameKotlinPsiProcessor : RenamePsiElementProcessor() {
return references 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? { override fun getElementToSearchInStringsAndComments(element: PsiElement): PsiElement? {
val unwrapped = element?.unwrapped ?: return null val unwrapped = element?.unwrapped ?: return null
if ((unwrapped is KtDeclaration) && KtPsiUtil.isLocal(unwrapped as KtDeclaration)) 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 && 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? { override fun getPostRenameCallback(element: PsiElement, newName: String, elementListener: RefactoringElementListener): Runnable? {
return Runnable { return Runnable {
element.ambiguousImportUsages?.forEach { element.ambiguousImportUsages?.forEach {
val ref = it.reference as? PsiPolyVariantReference ?: return@forEach val ref = it.reference as? PsiPolyVariantReference ?: return@forEach
if (ref.multiResolve(false).isEmpty()) { if (ref.multiResolve(false).isEmpty()) {
ref.handleElementRename(newName) if (!renameUsageIfPossible(it, element, newName)) {
ref.handleElementRename(newName)
}
} }
else { else {
ref.element?.getStrictParentOfType<KtImportDirective>()?.let { importDirective -> ref.element?.getStrictParentOfType<KtImportDirective>()?.let { importDirective ->
@@ -24,6 +24,7 @@ import com.intellij.psi.search.UsageSearchContext
import com.intellij.psi.search.searches.MethodReferencesSearch import com.intellij.psi.search.searches.MethodReferencesSearch
import com.intellij.psi.util.MethodSignatureUtil import com.intellij.psi.util.MethodSignatureUtil
import com.intellij.psi.util.TypeConversionUtil import com.intellij.psi.util.TypeConversionUtil
import org.jetbrains.kotlin.asJava.elements.KtLightMethod
import org.jetbrains.kotlin.asJava.toLightMethods import org.jetbrains.kotlin.asJava.toLightMethods
import org.jetbrains.kotlin.compatibility.ExecutorProcessor import org.jetbrains.kotlin.compatibility.ExecutorProcessor
import org.jetbrains.kotlin.idea.references.KtSimpleNameReference 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.references.readWriteAccess
import org.jetbrains.kotlin.idea.search.restrictToKotlinSources import org.jetbrains.kotlin.idea.search.restrictToKotlinSources
import org.jetbrains.kotlin.idea.util.runReadActionInSmartMode 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.JvmAbi
import org.jetbrains.kotlin.load.java.getPropertyNamesCandidatesByAccessorName 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.name.Name
import org.jetbrains.kotlin.psi.KtCallableDeclaration import org.jetbrains.kotlin.psi.KtCallableDeclaration
import org.jetbrains.kotlin.psi.KtNamedFunction import org.jetbrains.kotlin.psi.KtNamedFunction
@@ -47,6 +50,26 @@ class KotlinOverridingMethodReferenceSearcher : MethodUsagesSearcher() {
return 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 { val searchScope = p.project.runReadActionInSmartMode {
p.effectiveSearchScope p.effectiveSearchScope
.intersectWith(method.useScope) .intersectWith(method.useScope)
@@ -0,0 +1,6 @@
class J extends X.Y {
@Override
public int newOverridableMethod$production_sources_for_module_light_idea_test_case(int x) {
return super.newOverridableMethod$production_sources_for_module_light_idea_test_case(x);
}
}
@@ -0,0 +1,21 @@
sealed class X {
internal abstract fun newOverridableMethod(x: Int): Int
abstract class Y : X() {
override fun newOverridableMethod(x: Int): Int = 1
}
class Z : Y() {
override fun newOverridableMethod(x: Int): Int =
if (x > 0) x
else super.newOverridableMethod(x)
}
}
fun get() : X? {
return X.Z()
}
fun test() {
get()?.newOverridableMethod(2)
}
@@ -0,0 +1,6 @@
class J extends X.Y {
@Override
public int overridableMethod$production_sources_for_module_light_idea_test_case(int x) {
return super.overridableMethod$production_sources_for_module_light_idea_test_case(x);
}
}
@@ -0,0 +1,21 @@
sealed class X {
internal abstract fun /*rename*/overridableMethod(x: Int): Int
abstract class Y : X() {
override fun overridableMethod(x: Int): Int = 1
}
class Z : Y() {
override fun overridableMethod(x: Int): Int =
if (x > 0) x
else super.overridableMethod(x)
}
}
fun get() : X? {
return X.Z()
}
fun test() {
get()?.overridableMethod(2)
}
@@ -0,0 +1,5 @@
{
"type": "MARKED_ELEMENT",
"mainFile": "test.kt",
"newName": "newOverridableMethod"
}
@@ -0,0 +1,11 @@
class J extends X.Y {
@Override
public int getNewOverridableVar$production_sources_for_module_light_idea_test_case() {
return super.getNewOverridableVar$production_sources_for_module_light_idea_test_case();
}
@Override
public void setNewOverridableVar$production_sources_for_module_light_idea_test_case(int value) {
super.setNewOverridableVar$production_sources_for_module_light_idea_test_case(value);
}
}
@@ -0,0 +1,24 @@
sealed class X {
internal abstract var newOverridableVar: Int
abstract class Y : X() {
override var newOverridableVar: Int
get() = 1
set(value) {}
}
class Z : Y() {
override var newOverridableVar: Int
get() = super.newOverridableVar
set(value) { super.newOverridableVar = value }
}
}
fun get() : X? {
return X.Z()
}
fun test() {
get()?.newOverridableVar
get()?.newOverridableVar = 3
}
@@ -0,0 +1,11 @@
class J extends X.Y {
@Override
public int getOverridableVar$production_sources_for_module_light_idea_test_case() {
return super.getOverridableVar$production_sources_for_module_light_idea_test_case();
}
@Override
public void setOverridableVar$production_sources_for_module_light_idea_test_case(int value) {
super.setOverridableVar$production_sources_for_module_light_idea_test_case(value);
}
}
@@ -0,0 +1,24 @@
sealed class X {
internal abstract var /*rename*/overridableVar: Int
abstract class Y : X() {
override var overridableVar: Int
get() = 1
set(value) {}
}
class Z : Y() {
override var overridableVar: Int
get() = super.overridableVar
set(value) { super.overridableVar = value }
}
}
fun get() : X? {
return X.Z()
}
fun test() {
get()?.overridableVar
get()?.overridableVar = 3
}
@@ -0,0 +1,5 @@
{
"type": "MARKED_ELEMENT",
"mainFile": "test.kt",
"newName": "newOverridableVar"
}
@@ -214,6 +214,16 @@ public class RenameTestGenerated extends AbstractRenameTest {
runTest("idea/testData/refactoring/rename/importAliasByRef/importAliasByRef.test"); runTest("idea/testData/refactoring/rename/importAliasByRef/importAliasByRef.test");
} }
@TestMetadata("internalFunWithOverrides/internalFunWithOverrides.test")
public void testInternalFunWithOverrides_InternalFunWithOverrides() throws Exception {
runTest("idea/testData/refactoring/rename/internalFunWithOverrides/internalFunWithOverrides.test");
}
@TestMetadata("internalVarWithOverrides/internalFunWithOverrides.test")
public void testInternalVarWithOverrides_InternalFunWithOverrides() throws Exception {
runTest("idea/testData/refactoring/rename/internalVarWithOverrides/internalFunWithOverrides.test");
}
@TestMetadata("javaClassImportAliasByRef/javaClassImportAliasByRef.test") @TestMetadata("javaClassImportAliasByRef/javaClassImportAliasByRef.test")
public void testJavaClassImportAliasByRef_JavaClassImportAliasByRef() throws Exception { public void testJavaClassImportAliasByRef_JavaClassImportAliasByRef() throws Exception {
runTest("idea/testData/refactoring/rename/javaClassImportAliasByRef/javaClassImportAliasByRef.test"); runTest("idea/testData/refactoring/rename/javaClassImportAliasByRef/javaClassImportAliasByRef.test");