Move to Companion Object: Forbid for functions/properties referencing type parameters of the containing class

#KT-13876 Fixed
This commit is contained in:
Alexey Sedunov
2016-09-19 17:41:37 +03:00
parent 4cd4b8781d
commit 72ff5dd2cc
5 changed files with 39 additions and 8 deletions
+1
View File
@@ -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
@@ -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");