ShortenReferences: fix false negative for object call chain

#KT-32320 Fixed
This commit is contained in:
Dmitry Gridin
2019-06-30 16:44:11 +07:00
parent 33914a3a94
commit 148eed2a12
4 changed files with 46 additions and 9 deletions
@@ -17,13 +17,11 @@ import org.jetbrains.kotlin.idea.caches.resolve.allowResolveInWriteAction
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
import org.jetbrains.kotlin.idea.imports.canBeReferencedViaImport import org.jetbrains.kotlin.idea.imports.canBeReferencedViaImport
import org.jetbrains.kotlin.idea.imports.getImportableTargets import org.jetbrains.kotlin.idea.imports.getImportableTargets
import org.jetbrains.kotlin.idea.references.mainReference
import org.jetbrains.kotlin.idea.util.* import org.jetbrains.kotlin.idea.util.*
import org.jetbrains.kotlin.incremental.components.NoLookupLocation import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.createSmartPointer import org.jetbrains.kotlin.psi.psiUtil.*
import org.jetbrains.kotlin.psi.psiUtil.getParentOfType
import org.jetbrains.kotlin.psi.psiUtil.getQualifiedExpressionForReceiver
import org.jetbrains.kotlin.psi.psiUtil.parents
import org.jetbrains.kotlin.renderer.DescriptorRenderer import org.jetbrains.kotlin.renderer.DescriptorRenderer
import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.calls.callUtil.getCall import org.jetbrains.kotlin.resolve.calls.callUtil.getCall
@@ -60,19 +58,19 @@ class ShortenReferences(val options: (KtElement) -> Options = { Options.DEFAULT
val RETAIN_COMPANION = ShortenReferences { Options(removeExplicitCompanion = false) } val RETAIN_COMPANION = ShortenReferences { Options(removeExplicitCompanion = false) }
fun canBePossibleToDropReceiver(element: KtDotQualifiedExpression, bindingContext: BindingContext): Boolean { fun canBePossibleToDropReceiver(element: KtDotQualifiedExpression, bindingContext: BindingContext): Boolean {
val receiver = element.receiverExpression val nameRef = when (val receiver = element.receiverExpression) {
val nameRef = when (receiver) {
is KtThisExpression -> return true is KtThisExpression -> return true
is KtNameReferenceExpression -> receiver is KtNameReferenceExpression -> receiver
is KtDotQualifiedExpression -> receiver.selectorExpression as? KtNameReferenceExpression ?: return false is KtDotQualifiedExpression -> receiver.selectorExpression as? KtNameReferenceExpression ?: return false
else -> return false else -> return false
} }
val targetDescriptor = bindingContext[BindingContext.REFERENCE_TARGET, nameRef] when (val targetDescriptor = bindingContext[BindingContext.REFERENCE_TARGET, nameRef]) {
when (targetDescriptor) {
is ClassDescriptor -> { is ClassDescriptor -> {
if (targetDescriptor.kind != ClassKind.OBJECT) return true if (targetDescriptor.kind != ClassKind.OBJECT) return true
// for object receiver we should additionally check that it's dispatch receiver (that is the member is inside the object) or not a receiver at all // for object receiver we should additionally check that it's dispatch receiver (that is the member is inside the object) or not a receiver at all
val resolvedCall = element.getResolvedCall(bindingContext) ?: return false val resolvedCall = element.getResolvedCall(bindingContext)
?: return element.getQualifiedElementSelector()?.mainReference?.resolveToDescriptors(bindingContext) != null
val receiverKind = resolvedCall.explicitReceiverKind val receiverKind = resolvedCall.explicitReceiverKind
return receiverKind == ExplicitReceiverKind.DISPATCH_RECEIVER || receiverKind == ExplicitReceiverKind.NO_EXPLICIT_RECEIVER return receiverKind == ExplicitReceiverKind.DISPATCH_RECEIVER || receiverKind == ExplicitReceiverKind.NO_EXPLICIT_RECEIVER
} }
@@ -0,0 +1,17 @@
package my.ada.adad.ad
import my.ada.adad.ad.Fixtures.Register.Domain.UserRepository
object Fixtures {
object Register {
object Domain {
object UserRepository {
const val authSuccess = true
}
}
}
}
fun test() {
my.ada.adad.ad.Fixtures.Register.Domain<caret>.UserRepository.authSuccess
}
@@ -0,0 +1,17 @@
package my.ada.adad.ad
import my.ada.adad.ad.Fixtures.Register.Domain.UserRepository
object Fixtures {
object Register {
object Domain {
object UserRepository {
const val authSuccess = true
}
}
}
}
fun test() {
UserRepository.authSuccess
}
@@ -8234,6 +8234,11 @@ public class LocalInspectionTestGenerated extends AbstractLocalInspectionTest {
runTest("idea/testData/inspectionsLocal/removeRedundantQualifierName/notApplicableTypeWithRuntime2.kt"); runTest("idea/testData/inspectionsLocal/removeRedundantQualifierName/notApplicableTypeWithRuntime2.kt");
} }
@TestMetadata("objectCallChain.kt")
public void testObjectCallChain() throws Exception {
runTest("idea/testData/inspectionsLocal/removeRedundantQualifierName/objectCallChain.kt");
}
@TestMetadata("secondaryConstructor.kt") @TestMetadata("secondaryConstructor.kt")
public void testSecondaryConstructor() throws Exception { public void testSecondaryConstructor() throws Exception {
runTest("idea/testData/inspectionsLocal/removeRedundantQualifierName/secondaryConstructor.kt"); runTest("idea/testData/inspectionsLocal/removeRedundantQualifierName/secondaryConstructor.kt");