Move to Companion Object: Warn if companion object already contains function with the same signature

#KT-13877 Fixed
This commit is contained in:
Alexey Sedunov
2016-09-20 18:01:28 +03:00
parent 72ff5dd2cc
commit 75481c34b4
4 changed files with 31 additions and 2 deletions
+1
View File
@@ -115,6 +115,7 @@ These artifacts include extensions for the types available in the latter JDKs, s
- [`KT-13874`](https://youtrack.jetbrains.com/issue/KT-13874) Move to Companion: Fix AssertionError on running refactoring from Conflicts View
- [`KT-13883`](https://youtrack.jetbrains.com/issue/KT-13883) Move to Companion Object: Fix exception when applied to class
- [`KT-13876`](https://youtrack.jetbrains.com/issue/KT-13876) Move to Companion Object: Forbid for functions/properties referencing type parameters of the containing class
- [`KT-13877`](https://youtrack.jetbrains.com/issue/KT-13877) Move to Companion Object: Warn if companion object already contains function with the same signature
##### New features
@@ -34,11 +34,13 @@ import com.intellij.usageView.UsageInfo
import com.intellij.util.SmartList
import com.intellij.util.containers.MultiMap
import org.jetbrains.kotlin.asJava.toLightClass
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.ClassDescriptorWithResolutionScopes
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptor
import org.jetbrains.kotlin.idea.codeInsight.DescriptorToSourceUtilsIde
import org.jetbrains.kotlin.idea.core.*
import org.jetbrains.kotlin.idea.refactoring.checkConflictsInteractively
import org.jetbrains.kotlin.idea.refactoring.move.OuterInstanceReferenceUsageInfo
@@ -64,6 +66,7 @@ import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver
import org.jetbrains.kotlin.resolve.scopes.receivers.ImplicitReceiver
import org.jetbrains.kotlin.util.findCallableMemberBySignature
class MoveMemberToCompanionObjectIntention : SelfTargetingRangeIntention<KtNamedDeclaration>(KtNamedDeclaration::class.java,
"Move to companion object") {
@@ -248,6 +251,8 @@ class MoveMemberToCompanionObjectIntention : SelfTargetingRangeIntention<KtNamed
override fun applyTo(element: KtNamedDeclaration, editor: Editor?) {
val project = element.project
val containingClass = element.containingClassOrObject as KtClass
if (element is KtClassOrObject) {
val nameSuggestions = if (traverseOuterInstanceReferences(element, true)) getNameSuggestionsForOuterInstance(element) else emptyList()
val outerInstanceName = nameSuggestions.firstOrNull()
@@ -258,7 +263,7 @@ class MoveMemberToCompanionObjectIntention : SelfTargetingRangeIntention<KtNamed
}
}
val moveDescriptor = MoveDeclarationsDescriptor(listOf(element),
KotlinMoveTargetForCompanion(element.containingClassOrObject!! as KtClass),
KotlinMoveTargetForCompanion(containingClass),
MoveDeclarationsDelegate.NestedClass(null, outerInstanceName),
moveCallback = MoveCallback { runTemplateForInstanceParam(movedClass!!, nameSuggestions, editor) })
MoveKotlinDeclarationsProcessor(project, moveDescriptor, mover).run()
@@ -271,7 +276,7 @@ class MoveMemberToCompanionObjectIntention : SelfTargetingRangeIntention<KtNamed
return CommonRefactoringUtil.showErrorHint(project, editor, "$description is overridden by declaration(s) in a subclass", text, null)
}
if (hasTypeParameterReferences(element.containingClassOrObject!!, element)) {
if (hasTypeParameterReferences(containingClass, element)) {
return CommonRefactoringUtil.showErrorHint(project, editor, "$description references type parameters of the containing class", text, null)
}
@@ -279,6 +284,16 @@ class MoveMemberToCompanionObjectIntention : SelfTargetingRangeIntention<KtNamed
val outerInstanceUsages = SmartList<UsageInfo>()
val conflicts = MultiMap<PsiElement, String>()
containingClass.getCompanionObjects().firstOrNull()?.let { companion ->
val companionDescriptor = companion.resolveToDescriptor() as ClassDescriptor
val callableDescriptor = element.resolveToDescriptor() as CallableMemberDescriptor
companionDescriptor.findCallableMemberBySignature(callableDescriptor)?.let {
DescriptorToSourceUtilsIde.getAnyDeclaration(project, it)
}?.let {
conflicts.putValue(it, "Companion object already contains ${RefactoringUIUtil.getDescription(it, false)}")
}
}
val outerInstanceReferences = collectOuterInstanceReferences(element)
if (outerInstanceReferences.isNotEmpty()) {
if (element is KtProperty) {
@@ -0,0 +1,7 @@
// SHOULD_FAIL_WITH: Companion object already contains function f1(Int)
class Test9{
fun <caret>f1(n: Int){}
companion object{
fun f1(n: Int){}
}
}
@@ -9133,6 +9133,12 @@ public class IntentionTestGenerated extends AbstractIntentionTest {
doTest(fileName);
}
@TestMetadata("redeclarationConflict.kt")
public void testRedeclarationConflict() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/moveToCompanion/redeclarationConflict.kt");
doTest(fileName);
}
@TestMetadata("topLevelFunction.kt")
public void testTopLevelFunction() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/moveToCompanion/topLevelFunction.kt");