Pull Up: Skip super members without explicit declarations

#KT-13124 Fixed
This commit is contained in:
Alexey Sedunov
2016-08-15 18:46:54 +03:00
parent 6766494581
commit 94c4b426f5
6 changed files with 55 additions and 9 deletions
+1
View File
@@ -269,6 +269,7 @@ Using 'this' as function argument in constructor of non-final class
- [`KT-13240`](https://youtrack.jetbrains.com/issue/KT-13240) Rename: Do not report shadowing conflict if redeclaration is detected - [`KT-13240`](https://youtrack.jetbrains.com/issue/KT-13240) Rename: Do not report shadowing conflict if redeclaration is detected
- [`KT-13253`](https://youtrack.jetbrains.com/issue/KT-13253) Rename: Report conflicts for constructor parameters - [`KT-13253`](https://youtrack.jetbrains.com/issue/KT-13253) Rename: Report conflicts for constructor parameters
- [`KT-12971`](https://youtrack.jetbrains.com/issue/KT-12971) Push Down: Do not specifiy visibility on generated overriding members - [`KT-12971`](https://youtrack.jetbrains.com/issue/KT-12971) Push Down: Do not specifiy visibility on generated overriding members
- [`KT-13124`](https://youtrack.jetbrains.com/issue/KT-13124) Pull Up: Skip super members without explicit declarations
##### New features ##### New features
@@ -18,6 +18,7 @@ package org.jetbrains.kotlin.idea.refactoring.pullUp
import com.intellij.openapi.util.Key import com.intellij.openapi.util.Key
import com.intellij.psi.PsiElement import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.idea.codeInsight.shorten.addToShorteningWaitSet import org.jetbrains.kotlin.idea.codeInsight.shorten.addToShorteningWaitSet
import org.jetbrains.kotlin.idea.imports.importableFqName import org.jetbrains.kotlin.idea.imports.importableFqName
@@ -27,9 +28,11 @@ import org.jetbrains.kotlin.idea.core.ShortenReferences
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.allChildren import org.jetbrains.kotlin.psi.psiUtil.allChildren
import org.jetbrains.kotlin.psi.psiUtil.getQualifiedExpressionForReceiver
import org.jetbrains.kotlin.psi.psiUtil.getQualifiedExpressionForReceiverOrThis import org.jetbrains.kotlin.psi.psiUtil.getQualifiedExpressionForReceiverOrThis
import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.calls.callUtil.getCalleeExpressionIfAny
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
import org.jetbrains.kotlin.resolve.calls.resolvedCallUtil.getExplicitReceiverValue import org.jetbrains.kotlin.resolve.calls.resolvedCallUtil.getExplicitReceiverValue
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue
@@ -53,8 +56,10 @@ fun markElements(
private fun visitSuperOrThis(expression: KtInstanceExpressionWithLabel) { private fun visitSuperOrThis(expression: KtInstanceExpressionWithLabel) {
if (targetClassDescriptor == null) return if (targetClassDescriptor == null) return
val referenceTarget = context[BindingContext.REFERENCE_TARGET, expression.instanceReference] val callee = expression.getQualifiedExpressionForReceiver()?.selectorExpression?.getCalleeExpressionIfAny() ?: return
if (referenceTarget == targetClassDescriptor) { val calleeTarget = callee.getResolvedCall(context)?.resultingDescriptor ?: return
if ((calleeTarget as? CallableMemberDescriptor)?.kind != CallableMemberDescriptor.Kind.DECLARATION) return
if (calleeTarget.containingDeclaration == targetClassDescriptor) {
expression.replaceWithTargetThis = true expression.replaceWithTargetThis = true
affectedElements.add(expression) affectedElements.add(expression)
} }
@@ -91,13 +91,13 @@ private fun KotlinPullUpData.checkClashWithSuperDeclaration(
member: KtNamedDeclaration, member: KtNamedDeclaration,
memberDescriptor: DeclarationDescriptor, memberDescriptor: DeclarationDescriptor,
conflicts: MultiMap<PsiElement, String>) { conflicts: MultiMap<PsiElement, String>) {
if (memberDescriptor is CallableMemberDescriptor) { if (memberDescriptor !is CallableMemberDescriptor) return
val clashingSuper = getClashingMemberInTargetClass(memberDescriptor)
if (clashingSuper != null && clashingSuper.modality != Modality.ABSTRACT) { val clashingSuper = getClashingMemberInTargetClass(memberDescriptor) ?: return
val message = "${targetClassDescriptor.renderForConflicts()} already contains ${memberDescriptor.renderForConflicts()}" if (clashingSuper.modality == Modality.ABSTRACT) return
conflicts.putValue(member, message.capitalize()) if (clashingSuper.kind != CallableMemberDescriptor.Kind.DECLARATION) return
} val message = "${targetClassDescriptor.renderForConflicts()} already contains ${memberDescriptor.renderForConflicts()}"
} conflicts.putValue(member, message.capitalize())
} }
private fun KotlinPullUpData.checkAccidentalOverrides( private fun KotlinPullUpData.checkAccidentalOverrides(
@@ -0,0 +1,17 @@
// TARGET_CLASS: B
open class A {
open fun callSuper() {
// Something important
}
}
open class B : A() {
}
class <caret>C : B() {
// INFO: {"checked": "true"}
override fun callSuper() {
super.callSuper() // We simply call up to the base class
}
}
@@ -0,0 +1,17 @@
// TARGET_CLASS: B
open class A {
open fun callSuper() {
// Something important
}
}
open class B : A() {
// INFO: {"checked": "true"}
override fun callSuper() {
super.callSuper() // We simply call up to the base class
}
}
class C : B() {
}
@@ -223,6 +223,12 @@ public class PullUpTestGenerated extends AbstractPullUpTest {
doKotlinTest(fileName); doKotlinTest(fileName);
} }
@TestMetadata("skipFakeOverrides.kt")
public void testSkipFakeOverrides() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/pullUp/k2k/skipFakeOverrides.kt");
doKotlinTest(fileName);
}
@TestMetadata("spaceAfterModifier.kt") @TestMetadata("spaceAfterModifier.kt")
public void testSpaceAfterModifier() throws Exception { public void testSpaceAfterModifier() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/pullUp/k2k/spaceAfterModifier.kt"); String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/pullUp/k2k/spaceAfterModifier.kt");