Move to Companion Object: Forbid for functions/properties referencing type parameters of the containing class
#KT-13876 Fixed
This commit is contained in:
@@ -114,6 +114,7 @@ These artifacts include extensions for the types available in the latter JDKs, s
|
||||
- [`KT-11483`](https://youtrack.jetbrains.com/issue/KT-11483) Move to Companion: Do not use qualified names as labels
|
||||
- [`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
|
||||
|
||||
##### New features
|
||||
|
||||
|
||||
+18
-8
@@ -36,12 +36,10 @@ import com.intellij.util.containers.MultiMap
|
||||
import org.jetbrains.kotlin.asJava.toLightClass
|
||||
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.core.CollectingNameValidator
|
||||
import org.jetbrains.kotlin.idea.core.KotlinNameSuggester
|
||||
import org.jetbrains.kotlin.idea.core.getOrCreateCompanionObject
|
||||
import org.jetbrains.kotlin.idea.core.replaced
|
||||
import org.jetbrains.kotlin.idea.core.*
|
||||
import org.jetbrains.kotlin.idea.refactoring.checkConflictsInteractively
|
||||
import org.jetbrains.kotlin.idea.refactoring.move.OuterInstanceReferenceUsageInfo
|
||||
import org.jetbrains.kotlin.idea.refactoring.move.collectOuterInstanceReferences
|
||||
@@ -53,7 +51,6 @@ import org.jetbrains.kotlin.idea.references.KtSimpleNameReference
|
||||
import org.jetbrains.kotlin.idea.search.declarationsSearch.HierarchySearchRequest
|
||||
import org.jetbrains.kotlin.idea.search.declarationsSearch.searchOverriders
|
||||
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers
|
||||
import org.jetbrains.kotlin.idea.core.ShortenReferences
|
||||
import org.jetbrains.kotlin.idea.util.application.runReadAction
|
||||
import org.jetbrains.kotlin.idea.util.application.runWriteAction
|
||||
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
||||
@@ -62,6 +59,7 @@ import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.*
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
|
||||
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver
|
||||
@@ -237,6 +235,14 @@ class MoveMemberToCompanionObjectIntention : SelfTargetingRangeIntention<KtNamed
|
||||
runTemplateForInstanceParam(newDeclaration, nameSuggestions, editor)
|
||||
}
|
||||
|
||||
private fun hasTypeParameterReferences(containingClass: KtClassOrObject, element: KtNamedDeclaration): Boolean {
|
||||
val containingClassDescriptor = containingClass.resolveToDescriptor()
|
||||
return element.collectDescendantsOfType<KtTypeReference> {
|
||||
val referencedDescriptor = it.analyze(BodyResolveMode.PARTIAL)[BindingContext.TYPE, it]?.constructor?.declarationDescriptor
|
||||
referencedDescriptor is TypeParameterDescriptor && referencedDescriptor.containingDeclaration == containingClassDescriptor
|
||||
}.isNotEmpty()
|
||||
}
|
||||
|
||||
override fun startInWriteAction() = false
|
||||
|
||||
override fun applyTo(element: KtNamedDeclaration, editor: Editor?) {
|
||||
@@ -259,10 +265,14 @@ class MoveMemberToCompanionObjectIntention : SelfTargetingRangeIntention<KtNamed
|
||||
return
|
||||
}
|
||||
|
||||
val description = RefactoringUIUtil.getDescription(element, false).capitalize()
|
||||
|
||||
if (HierarchySearchRequest(element, element.useScope, false).searchOverriders().any()) {
|
||||
val description = RefactoringUIUtil.getDescription(element, false).capitalize()
|
||||
CommonRefactoringUtil.showErrorHint(project, editor, "$description is overridden by declaration(s) in a subclass", text, null)
|
||||
return
|
||||
return CommonRefactoringUtil.showErrorHint(project, editor, "$description is overridden by declaration(s) in a subclass", text, null)
|
||||
}
|
||||
|
||||
if (hasTypeParameterReferences(element.containingClassOrObject!!, element)) {
|
||||
return CommonRefactoringUtil.showErrorHint(project, editor, "$description references type parameters of the containing class", text, null)
|
||||
}
|
||||
|
||||
val externalUsages = SmartList<UsageInfo>()
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
// SHOULD_FAIL_WITH: Function <b><code>genericFunT()</code></b> references type parameters of the containing class
|
||||
class Test6<T>(val t: T) {
|
||||
fun <caret>genericFunT(): T = t
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
// SHOULD_FAIL_WITH: Property <b><code>genericValT</code></b> references type parameters of the containing class
|
||||
class Test6<T>(val t: T) {
|
||||
val <caret>genericValT: T get() = t
|
||||
}
|
||||
@@ -9067,6 +9067,18 @@ public class IntentionTestGenerated extends AbstractIntentionTest {
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("genericFunction.kt")
|
||||
public void testGenericFunction() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/moveToCompanion/genericFunction.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("genericProperty.kt")
|
||||
public void testGenericProperty() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/moveToCompanion/genericProperty.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("implicitDispatchReceiver.kt")
|
||||
public void testImplicitDispatchReceiver() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/moveToCompanion/implicitDispatchReceiver.kt");
|
||||
|
||||
Reference in New Issue
Block a user