Rename: Qualify references to members of enum companions in case of conflict with enum entries
#KT-10033 Fixed (cherry picked from commit 3373d54)
This commit is contained in:
@@ -242,6 +242,7 @@
|
||||
- [`KT-9435`](https://youtrack.jetbrains.com/issue/KT-9435) Process property accesor usages (Java) in comments and string literals
|
||||
- [`KT-9444`](https://youtrack.jetbrains.com/issue/KT-9444) Rename dialog: Allow typing any identifier without backquotes
|
||||
- [`KT-9446`](https://youtrack.jetbrains.com/issue/KT-9446) Copy default parameter values to overriding function which is renamed while its base function is not
|
||||
- [`KT-10033`](https://youtrack.jetbrains.com/issue/KT-10033) Qualify references to members of enum companions in case of conflict with enum entries
|
||||
- [`KT-10713`](https://youtrack.jetbrains.com/issue/KT-10713) Skip read-only declarations when renaming parameters
|
||||
- [`KT-10687`](https://youtrack.jetbrains.com/issue/KT-10687) Qualify property references to avoid shadowing by parameters
|
||||
- [`KT-12543`](https://youtrack.jetbrains.com/issue/KT-12543) Qualify property references with 'this' to avoid renaming conflicts
|
||||
|
||||
@@ -21,10 +21,7 @@ import com.intellij.psi.PsiDocumentManager
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.impl.source.PostprocessReformattingAspect
|
||||
import com.intellij.psi.util.PsiTreeUtil
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ClassifierDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.PackageViewDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.idea.analysis.analyzeInContext
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
|
||||
import org.jetbrains.kotlin.idea.core.ShortenReferences.Options
|
||||
@@ -46,6 +43,7 @@ import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ImplicitReceiver
|
||||
import org.jetbrains.kotlin.resolve.scopes.utils.findClassifier
|
||||
import org.jetbrains.kotlin.resolve.scopes.utils.findPackage
|
||||
import org.jetbrains.kotlin.resolve.source.getPsi
|
||||
import org.jetbrains.kotlin.utils.singletonOrEmptyList
|
||||
import java.util.*
|
||||
|
||||
@@ -469,6 +467,11 @@ class ShortenReferences(val options: (KtElement) -> Options = { Options.DEFAULT
|
||||
|
||||
val selectorsSelectorTarget = selectorsSelector.singleTarget(bindingContext) ?: return false
|
||||
if (selectorsSelectorTarget is ClassDescriptor) return false
|
||||
// TODO: More generic solution may be possible
|
||||
if (selectorsSelectorTarget is PropertyDescriptor) {
|
||||
val source = selectorsSelectorTarget.source.getPsi() as? KtProperty
|
||||
if (source != null && isEnumCompanionPropertyWithEntryConflict(source, source.name ?: "")) return false
|
||||
}
|
||||
|
||||
addElementToShorten(qualifiedExpression)
|
||||
return true
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package org.jetbrains.kotlin.idea.core
|
||||
|
||||
import com.intellij.psi.PsiElement
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.idea.analysis.computeTypeInContext
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
||||
@@ -27,6 +28,7 @@ import org.jetbrains.kotlin.idea.resolve.frontendService
|
||||
import org.jetbrains.kotlin.idea.util.getImplicitReceiversWithInstanceToExpression
|
||||
import org.jetbrains.kotlin.idea.util.getResolutionScope
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.containingClassOrObject
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getQualifiedElementSelector
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getQualifiedExpressionForSelectorOrThis
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
@@ -159,4 +161,16 @@ fun KtCallableDeclaration.canOmitDeclaredType(initializerOrBodyExpression: KtExp
|
||||
return canChangeTypeToSubtype && expressionType.isSubtypeOf(declaredType)
|
||||
}
|
||||
|
||||
fun String.quoteIfNeeded(): String = if (KotlinNameSuggester.isIdentifier(this)) this else "`$this`"
|
||||
fun String.quoteIfNeeded(): String = if (KotlinNameSuggester.isIdentifier(this)) this else "`$this`"
|
||||
|
||||
fun isEnumCompanionPropertyWithEntryConflict(element: PsiElement, expectedName: String): Boolean {
|
||||
if (element !is KtProperty) return false
|
||||
|
||||
val propertyClass = element.containingClassOrObject as? KtObjectDeclaration ?: return false
|
||||
if (!propertyClass.isCompanion()) return false
|
||||
|
||||
val outerClass = propertyClass.containingClassOrObject as? KtClass ?: return false
|
||||
if (!outerClass.isEnum()) return false
|
||||
|
||||
return outerClass.declarations.any { it is KtEnumEntry && it.name == expectedName }
|
||||
}
|
||||
+16
-1
@@ -26,6 +26,7 @@ import com.intellij.psi.search.searches.OverridingMethodsSearch
|
||||
import com.intellij.refactoring.JavaRefactoringSettings
|
||||
import com.intellij.refactoring.listeners.RefactoringElementListener
|
||||
import com.intellij.refactoring.rename.RenameProcessor
|
||||
import com.intellij.refactoring.util.MoveRenameUsageInfo
|
||||
import com.intellij.refactoring.util.RefactoringUtil
|
||||
import com.intellij.usageView.UsageInfo
|
||||
import com.intellij.usageView.UsageViewUtil
|
||||
@@ -36,9 +37,11 @@ import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.VariableDescriptor
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptor
|
||||
import org.jetbrains.kotlin.idea.core.isEnumCompanionPropertyWithEntryConflict
|
||||
import org.jetbrains.kotlin.idea.refactoring.dropOverrideKeywordIfNecessary
|
||||
import org.jetbrains.kotlin.idea.references.KtReference
|
||||
import org.jetbrains.kotlin.idea.references.KtSimpleNameReference
|
||||
import org.jetbrains.kotlin.idea.references.mainReference
|
||||
import org.jetbrains.kotlin.idea.util.application.runReadAction
|
||||
import org.jetbrains.kotlin.lexer.KtTokens
|
||||
import org.jetbrains.kotlin.load.java.JvmAbi
|
||||
@@ -283,7 +286,7 @@ class RenameKotlinPropertyProcessor : RenameKotlinPsiProcessor() {
|
||||
SETTER_USAGE
|
||||
}
|
||||
|
||||
override tailrec fun renameElement(element: PsiElement, newName: String, usages: Array<out UsageInfo>, listener: RefactoringElementListener?) {
|
||||
override tailrec fun renameElement(element: PsiElement, newName: String, usages: Array<UsageInfo>, listener: RefactoringElementListener?) {
|
||||
if (element is KtLightMethod) {
|
||||
if (element.modifierList.findAnnotation(DescriptorUtils.JVM_NAME.asString()) != null) {
|
||||
return super.renameElement(element, newName, usages, listener)
|
||||
@@ -309,6 +312,18 @@ class RenameKotlinPropertyProcessor : RenameKotlinPsiProcessor() {
|
||||
val oldGetterName = JvmAbi.getterName(name)
|
||||
val oldSetterName = JvmAbi.setterName(name)
|
||||
|
||||
if (isEnumCompanionPropertyWithEntryConflict(element, newName)) {
|
||||
for ((i, usage) in usages.withIndex()) {
|
||||
if (usage !is MoveRenameUsageInfo) continue
|
||||
val ref = usage.reference ?: continue
|
||||
// TODO: Enum value can't be accessed from Java in case of conflict with companion member
|
||||
if (ref is KtReference) {
|
||||
val newRef = (ref.bindToElement(element) as? KtSimpleNameExpression)?.mainReference ?: continue
|
||||
usages[i] = MoveRenameUsageInfo(newRef, usage.referencedElement)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val adjustedUsages = if (element is KtParameter) usages.filterNot {
|
||||
val refTarget = it.reference?.resolve()
|
||||
refTarget is KtLightMethod && isComponentLike(Name.guessByFirstCharacter(refTarget.name))
|
||||
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
package test;
|
||||
|
||||
class Test {
|
||||
{
|
||||
E e = E.A;
|
||||
int n = E.A;
|
||||
}
|
||||
}
|
||||
Vendored
+13
@@ -0,0 +1,13 @@
|
||||
package test
|
||||
|
||||
enum class E {
|
||||
A;
|
||||
|
||||
companion object {
|
||||
public const val A: Int = 1
|
||||
}
|
||||
}
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
val a = E.Companion.A + 2
|
||||
}
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
package test;
|
||||
|
||||
class Test {
|
||||
{
|
||||
E e = E.A;
|
||||
int n = E.B;
|
||||
}
|
||||
}
|
||||
Vendored
+13
@@ -0,0 +1,13 @@
|
||||
package test
|
||||
|
||||
enum class E {
|
||||
A;
|
||||
|
||||
companion object {
|
||||
public const val /*rename*/B : Int = 1
|
||||
}
|
||||
}
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
val a = E.B + 2
|
||||
}
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"type": "MARKED_ELEMENT",
|
||||
"mainFile": "test/test.kt",
|
||||
"newName": "A",
|
||||
"withRuntime": "true"
|
||||
}
|
||||
@@ -893,6 +893,12 @@ public class RenameTestGenerated extends AbstractRenameTest {
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("renamePropertyInEnumCompanionWithEntryConflict/renameKotlinPropertyInEnumCompanionWithEntryConflict.test")
|
||||
public void testRenamePropertyInEnumCompanionWithEntryConflict_RenameKotlinPropertyInEnumCompanionWithEntryConflict() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/rename/renamePropertyInEnumCompanionWithEntryConflict/renameKotlinPropertyInEnumCompanionWithEntryConflict.test");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("renameSet/set.test")
|
||||
public void testRenameSet_Set() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/rename/renameSet/set.test");
|
||||
|
||||
Reference in New Issue
Block a user