Move: Fix processing of references to non-real members of companion object

#KT-15559 Fixed
This commit is contained in:
Alexey Sedunov
2017-03-12 19:04:42 +03:00
parent bab762b761
commit 6f5249ecc7
21 changed files with 273 additions and 7 deletions
@@ -142,7 +142,7 @@ class MoveKotlinDeclarationsProcessor(
.search(lightElement, projectScope, false)
.mapNotNullTo(ArrayList()) { ref ->
if (foundReferences.add(ref) && elementsToMove.all { !it.isAncestor(ref.element)}) {
createMoveUsageInfoIfPossible(ref, lightElement, true)
createMoveUsageInfoIfPossible(ref, lightElement, true, null)
}
else null
}
@@ -121,8 +121,13 @@ fun KtElement.lazilyProcessInternalReferencesToUpdateOnPackageNameChange(
fun processReference(refExpr: KtSimpleNameExpression, bindingContext: BindingContext): ((KtSimpleNameExpression) -> UsageInfo?)? {
val descriptor = bindingContext[BindingContext.REFERENCE_TARGET, refExpr]?.getImportableDescriptor() ?: return null
val containingDescriptor = descriptor.containingDeclaration ?: return null
val declaration = DescriptorToSourceUtilsIde.getAnyDeclaration(project, descriptor) ?: return null
val callableKind = (descriptor as? CallableMemberDescriptor)?.kind
val containingDeclarationForNonRealMember = if (callableKind != CallableMemberDescriptor.Kind.DECLARATION) {
DescriptorToSourceUtilsIde.getAnyDeclaration(project, containingDescriptor) as? KtClassOrObject
} else null
// Special case for enum entry superclass references (they have empty text and don't need to be processed by the refactoring)
if (refExpr.textRange.isEmpty) return null
@@ -134,7 +139,6 @@ fun KtElement.lazilyProcessInternalReferencesToUpdateOnPackageNameChange(
val isCallableReference = isCallableReference(refExpr.mainReference)
if (isCallable && !isCallableReference) {
val containingDescriptor = descriptor.containingDeclaration
if (isExtension && containingDescriptor is ClassDescriptor) {
val implicitClass = (refExpr.getResolvedCall(bindingContext)?.dispatchReceiver as? ImplicitClassReceiver)?.classDescriptor
if (DescriptorUtils.isCompanionObject(implicitClass)) {
@@ -174,7 +178,8 @@ fun KtElement.lazilyProcessInternalReferencesToUpdateOnPackageNameChange(
.firstOrNull()
fun doCreateUsageInfo(refExpr: KtSimpleNameExpression): UsageInfo? {
if (isAncestor(declaration, false)) {
// Check container instead of declaration itself as the latter may be not real (e.g. fake override)
if (isAncestor(containingDeclarationForNonRealMember ?: declaration, false)) {
if (descriptor.importableFqName == null) return null
if (isUnqualifiedExtensionReference(refExpr.mainReference, declaration)) return null
if (isCallableReference(refExpr.mainReference)) return null
@@ -192,7 +197,7 @@ fun KtElement.lazilyProcessInternalReferencesToUpdateOnPackageNameChange(
}
}
return createMoveUsageInfoIfPossible(refExpr.mainReference, declaration, false)
return createMoveUsageInfoIfPossible(refExpr.mainReference, declaration, false, fqName.toSafe())
}
if (isExtension || isCallableReference || containerFqName != null || isImported(descriptor)) return ::doCreateUsageInfo
@@ -226,10 +231,20 @@ class MoveRenameSelfUsageInfo(ref: KtSimpleNameReference, refTarget: PsiElement,
override fun getReference() = super.getReference() as? KtSimpleNameReference
}
class QualifiableMoveRenameUsageInfo(
element: PsiElement,
reference: PsiReference,
startOffset: Int,
endOffset: Int,
referencedElement: PsiElement,
val newFqName: FqName?
): MoveRenameUsageInfo(element, reference, startOffset, endOffset, referencedElement, false)
fun createMoveUsageInfoIfPossible(
reference: PsiReference,
referencedElement: PsiElement,
addImportToOriginalFile: Boolean
addImportToOriginalFile: Boolean,
newFqName: FqName?
): UsageInfo? {
val element = reference.element
if (element.getStrictParentOfType<KtSuperExpression>() != null) return null
@@ -243,7 +258,7 @@ fun createMoveUsageInfoIfPossible(
element, reference, startOffset, endOffset, referencedElement, element.containingFile!!, addImportToOriginalFile
)
}
return MoveRenameUsageInfo(element, reference, startOffset, endOffset, referencedElement, false)
return QualifiableMoveRenameUsageInfo(element, reference, startOffset, endOffset, referencedElement, newFqName)
}
private fun isUnqualifiedExtensionReference(reference: PsiReference, referencedElement: PsiElement): Boolean {
@@ -351,7 +366,15 @@ fun postProcessMoveUsages(usages: Collection<UsageInfo>,
val reference = usage.reference ?: (usage.element as? KtSimpleNameExpression)?.mainReference
try {
when {
reference is KtSimpleNameReference -> reference.bindToElement(newElement, shorteningMode)
reference is KtSimpleNameReference -> {
val newFqName = (usage as? QualifiableMoveRenameUsageInfo)?.newFqName
if (newFqName != null) {
reference.bindToFqName(newFqName, shorteningMode)
}
else {
reference.bindToElement(newElement, shorteningMode)
}
}
reference is PsiReferenceExpression && updateJavaReference(reference, oldElement, newElement) -> continue@usageLoop
else -> reference?.bindToElement(newElement)
}
@@ -0,0 +1,13 @@
package source
class Logger {
fun debug(s: () -> String) {
}
}
open class Klogging
val Klogging.loggerExt: Logger get() = Logger
fun Klogging.logExt(s: String) {}
@@ -0,0 +1,14 @@
package target
import source.Klogging
import source.logExt
import source.loggerExt
class Foo {
companion object : Klogging()
fun baz() {
loggerExt.debug { "something" }
logExt("something")
}
}
@@ -0,0 +1,21 @@
package source
class Logger {
fun debug(s: () -> String) {
}
}
open class Klogging
val Klogging.loggerExt: Logger get() = Logger
fun Klogging.logExt(s: String) {}
class <caret>Foo {
companion object : Klogging()
fun baz() {
loggerExt.debug { "something" }
logExt("something")
}
}
@@ -0,0 +1,5 @@
{
"mainFile": "source/Foo.kt",
"type": "MOVE_KOTLIN_TOP_LEVEL_DECLARATIONS",
"targetPackage": "target"
}
@@ -0,0 +1,18 @@
package source
class Logger {
fun debug(s: () -> String) {
}
}
interface ILogging {
val logger: Logger
fun log(s: String)
}
class Klogging : ILogging {
override val logger = Logger()
override fun log(s: String) {}
}
@@ -0,0 +1,13 @@
package target
import source.ILogging
import source.Klogging
class Foo {
companion object : ILogging by Klogging()
fun baz() {
logger.debug { "something" }
log("something")
}
}
@@ -0,0 +1,26 @@
package source
class Logger {
fun debug(s: () -> String) {
}
}
interface ILogging {
val logger: Logger
fun log(s: String)
}
class Klogging : ILogging {
override val logger = Logger()
override fun log(s: String) {}
}
class <caret>Foo {
companion object : ILogging by Klogging()
fun baz() {
logger.debug { "something" }
log("something")
}
}
@@ -0,0 +1,5 @@
{
"mainFile": "source/Foo.kt",
"type": "MOVE_KOTLIN_TOP_LEVEL_DECLARATIONS",
"targetPackage": "target"
}
@@ -0,0 +1,13 @@
package source
class Logger {
fun debug(s: () -> String) {
}
}
open class Klogging {
val logger = Logger()
fun log(s: String) {}
}
@@ -0,0 +1,12 @@
package target
import source.Klogging
class Foo {
companion object : Klogging()
fun baz() {
logger.debug { "something" }
log("something")
}
}
@@ -0,0 +1,21 @@
package source
class Logger {
fun debug(s: () -> String) {
}
}
open class Klogging {
val logger = Logger()
fun log(s: String) {}
}
class <caret>Foo {
companion object : Klogging()
fun baz() {
logger.debug { "something" }
log("something")
}
}
@@ -0,0 +1,5 @@
{
"mainFile": "source/Foo.kt",
"type": "MOVE_KOTLIN_TOP_LEVEL_DECLARATIONS",
"targetPackage": "target"
}
@@ -0,0 +1,8 @@
package source
class Logger {
fun debug(s: () -> String) {
}
}
@@ -0,0 +1,6 @@
package source;
public class Klogging {
public Logger logger = Logger();
public void log(String s) {}
}
@@ -0,0 +1,12 @@
package target
import source.Klogging
class Foo {
companion object : Klogging()
fun baz() {
logger.debug { "something" }
log("something")
}
}
@@ -0,0 +1,16 @@
package source
class Logger {
fun debug(s: () -> String) {
}
}
class <caret>Foo {
companion object : Klogging()
fun baz() {
logger.debug { "something" }
log("something")
}
}
@@ -0,0 +1,6 @@
package source;
public class Klogging {
public Logger logger = Logger();
public void log(String s) {}
}
@@ -0,0 +1,5 @@
{
"mainFile": "source/Foo.kt",
"type": "MOVE_KOTLIN_TOP_LEVEL_DECLARATIONS",
"targetPackage": "target"
}
@@ -414,6 +414,30 @@ public class MoveTestGenerated extends AbstractMoveTest {
doTest(fileName);
}
@TestMetadata("kotlin/moveTopLevelDeclarations/misc/companionExtensionMemberRef/companionExtensionMemberRef.test")
public void testKotlin_moveTopLevelDeclarations_misc_companionExtensionMemberRef_CompanionExtensionMemberRef() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/move/kotlin/moveTopLevelDeclarations/misc/companionExtensionMemberRef/companionExtensionMemberRef.test");
doTest(fileName);
}
@TestMetadata("kotlin/moveTopLevelDeclarations/misc/companionMemberRefDelegation/companionMemberRefDelegation.test")
public void testKotlin_moveTopLevelDeclarations_misc_companionMemberRefDelegation_CompanionMemberRefDelegation() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/move/kotlin/moveTopLevelDeclarations/misc/companionMemberRefDelegation/companionMemberRefDelegation.test");
doTest(fileName);
}
@TestMetadata("kotlin/moveTopLevelDeclarations/misc/companionMemberRefFakeOverride/companionMemberRefFakeOverride.test")
public void testKotlin_moveTopLevelDeclarations_misc_companionMemberRefFakeOverride_CompanionMemberRefFakeOverride() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/move/kotlin/moveTopLevelDeclarations/misc/companionMemberRefFakeOverride/companionMemberRefFakeOverride.test");
doTest(fileName);
}
@TestMetadata("kotlin/moveTopLevelDeclarations/misc/companionMemberRefWithJavaParent/companionMemberRefWithJavaParent.test")
public void testKotlin_moveTopLevelDeclarations_misc_companionMemberRefWithJavaParent_CompanionMemberRefWithJavaParent() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/move/kotlin/moveTopLevelDeclarations/misc/companionMemberRefWithJavaParent/companionMemberRefWithJavaParent.test");
doTest(fileName);
}
@TestMetadata("kotlin/moveTopLevelDeclarations/misc/delegateInObject/delegateInObject.test")
public void testKotlin_moveTopLevelDeclarations_misc_delegateInObject_DelegateInObject() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/move/kotlin/moveTopLevelDeclarations/misc/delegateInObject/delegateInObject.test");