MakeOverriddenMemberOpenFix: should update actual members
#KT-32586 Fixed
This commit is contained in:
@@ -97,7 +97,7 @@ private fun MemberDescriptor.isConstructorInActual(checkConstructor: Boolean) =
|
|||||||
private fun MemberDescriptor.isEnumEntryInActual() =
|
private fun MemberDescriptor.isEnumEntryInActual() =
|
||||||
(DescriptorUtils.isEnumEntry(this) && (containingDeclaration as? MemberDescriptor)?.isActual == true)
|
(DescriptorUtils.isEnumEntry(this) && (containingDeclaration as? MemberDescriptor)?.isActual == true)
|
||||||
|
|
||||||
private fun DeclarationDescriptor.actualsForExpected(): Collection<DeclarationDescriptor> {
|
fun DeclarationDescriptor.actualsForExpected(): Collection<DeclarationDescriptor> {
|
||||||
if (this is MemberDescriptor) {
|
if (this is MemberDescriptor) {
|
||||||
if (!this.isExpect) return emptyList()
|
if (!this.isExpect) return emptyList()
|
||||||
|
|
||||||
|
|||||||
@@ -13,12 +13,16 @@ import com.intellij.psi.util.CachedValueProvider
|
|||||||
import com.intellij.psi.util.PsiModificationTracker
|
import com.intellij.psi.util.PsiModificationTracker
|
||||||
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
|
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor.Kind.*
|
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor.Kind.*
|
||||||
|
import org.jetbrains.kotlin.descriptors.MemberDescriptor
|
||||||
|
import org.jetbrains.kotlin.descriptors.Modality
|
||||||
import org.jetbrains.kotlin.descriptors.isOverridable
|
import org.jetbrains.kotlin.descriptors.isOverridable
|
||||||
import org.jetbrains.kotlin.diagnostics.Diagnostic
|
import org.jetbrains.kotlin.diagnostics.Diagnostic
|
||||||
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptorIfAny
|
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptorIfAny
|
||||||
import org.jetbrains.kotlin.idea.core.util.CachedValue
|
import org.jetbrains.kotlin.idea.core.util.CachedValue
|
||||||
import org.jetbrains.kotlin.idea.core.util.getValue
|
import org.jetbrains.kotlin.idea.core.util.getValue
|
||||||
import org.jetbrains.kotlin.idea.refactoring.canRefactor
|
import org.jetbrains.kotlin.idea.refactoring.canRefactor
|
||||||
|
import org.jetbrains.kotlin.idea.util.actualsForExpected
|
||||||
|
import org.jetbrains.kotlin.idea.util.isExpectDeclaration
|
||||||
import org.jetbrains.kotlin.lexer.KtTokens.OPEN_KEYWORD
|
import org.jetbrains.kotlin.lexer.KtTokens.OPEN_KEYWORD
|
||||||
import org.jetbrains.kotlin.psi.KtCallableDeclaration
|
import org.jetbrains.kotlin.psi.KtCallableDeclaration
|
||||||
import org.jetbrains.kotlin.psi.KtDeclaration
|
import org.jetbrains.kotlin.psi.KtDeclaration
|
||||||
@@ -56,6 +60,17 @@ class MakeOverriddenMemberOpenFix(declaration: KtDeclaration) : KotlinQuickFixAc
|
|||||||
) {
|
) {
|
||||||
return QUICKFIX_UNAVAILABLE
|
return QUICKFIX_UNAVAILABLE
|
||||||
}
|
}
|
||||||
|
|
||||||
|
overriddenDescriptor.takeIf { overriddenMember.isExpectDeclaration() }?.actualsForExpected()?.forEach {
|
||||||
|
if (it is MemberDescriptor && it.modality < Modality.OPEN) {
|
||||||
|
val member = DescriptorToSourceUtils.descriptorToDeclaration(it)
|
||||||
|
if (member == null || !member.canRefactor() || member !is KtCallableDeclaration) {
|
||||||
|
return QUICKFIX_UNAVAILABLE
|
||||||
|
}
|
||||||
|
overriddenNonOverridableMembers.add(member.createSmartPointer())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
val containingDeclarationName = overriddenDescriptor.containingDeclaration.name.asString()
|
val containingDeclarationName = overriddenDescriptor.containingDeclaration.name.asString()
|
||||||
overriddenNonOverridableMembers.add(overriddenMember.createSmartPointer())
|
overriddenNonOverridableMembers.add(overriddenMember.createSmartPointer())
|
||||||
containingDeclarationsNames.add(containingDeclarationName)
|
containingDeclarationsNames.add(containingDeclarationName)
|
||||||
@@ -69,7 +84,7 @@ class MakeOverriddenMemberOpenFix(declaration: KtDeclaration) : KotlinQuickFixAc
|
|||||||
|
|
||||||
override fun getText(): String {
|
override fun getText(): String {
|
||||||
val element = element ?: return ""
|
val element = element ?: return ""
|
||||||
if (overriddenNonOverridableMembers.size == 1) {
|
if (containingDeclarationsNames.size == 1) {
|
||||||
val name = containingDeclarationsNames[0] + "." + element.name
|
val name = containingDeclarationsNames[0] + "." + element.name
|
||||||
return "Make $name $OPEN_KEYWORD"
|
return "Make $name $OPEN_KEYWORD"
|
||||||
}
|
}
|
||||||
|
|||||||
+3
@@ -0,0 +1,3 @@
|
|||||||
|
expect open class OClass() {
|
||||||
|
val overrideMe: String
|
||||||
|
}
|
||||||
+3
@@ -0,0 +1,3 @@
|
|||||||
|
expect open class OClass() {
|
||||||
|
val overrideMe: String
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
// "Make OClass.overrideMe open" "true"
|
||||||
|
|
||||||
|
actual open class OClass actual constructor() {
|
||||||
|
actual val overrideMe: String = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
class Another: OClass() {
|
||||||
|
override<caret> val overrideMe = ""
|
||||||
|
}
|
||||||
+9
@@ -0,0 +1,9 @@
|
|||||||
|
// "Make OClass.overrideMe open" "true"
|
||||||
|
|
||||||
|
actual open class OClass actual constructor() {
|
||||||
|
actual open val overrideMe: String = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
class Another: OClass() {
|
||||||
|
override val overrideMe = ""
|
||||||
|
}
|
||||||
+9
@@ -0,0 +1,9 @@
|
|||||||
|
// "Make OClass.overrideMe open" "true"
|
||||||
|
|
||||||
|
expect open class OClass() {
|
||||||
|
val overrideMe: String
|
||||||
|
}
|
||||||
|
|
||||||
|
class Another: OClass() {
|
||||||
|
override<caret> val overrideMe = ""
|
||||||
|
}
|
||||||
+9
@@ -0,0 +1,9 @@
|
|||||||
|
// "Make OClass.overrideMe open" "true"
|
||||||
|
|
||||||
|
expect open class OClass() {
|
||||||
|
open val overrideMe: String
|
||||||
|
}
|
||||||
|
|
||||||
|
class Another: OClass() {
|
||||||
|
override val overrideMe = ""
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
actual open class OClass actual constructor() {
|
||||||
|
actual val overrideMe: String = ""
|
||||||
|
}
|
||||||
+3
@@ -0,0 +1,3 @@
|
|||||||
|
actual open class OClass actual constructor() {
|
||||||
|
actual open val overrideMe: String = ""
|
||||||
|
}
|
||||||
+9
@@ -0,0 +1,9 @@
|
|||||||
|
// "Make OClass.overrideMe open" "true"
|
||||||
|
|
||||||
|
expect open class OClass() {
|
||||||
|
val overrideMe: String
|
||||||
|
}
|
||||||
|
|
||||||
|
class Another: OClass() {
|
||||||
|
override<caret> val overrideMe = ""
|
||||||
|
}
|
||||||
Vendored
+9
@@ -0,0 +1,9 @@
|
|||||||
|
// "Make OClass.overrideMe open" "true"
|
||||||
|
|
||||||
|
expect open class OClass() {
|
||||||
|
open val overrideMe: String
|
||||||
|
}
|
||||||
|
|
||||||
|
class Another: OClass() {
|
||||||
|
override val overrideMe = ""
|
||||||
|
}
|
||||||
+3
@@ -0,0 +1,3 @@
|
|||||||
|
actual abstract class OClass actual constructor() {
|
||||||
|
actual abstract val overrideMe: String
|
||||||
|
}
|
||||||
+3
@@ -0,0 +1,3 @@
|
|||||||
|
actual abstract class OClass actual constructor() {
|
||||||
|
actual abstract val overrideMe: String
|
||||||
|
}
|
||||||
+9
@@ -0,0 +1,9 @@
|
|||||||
|
// "Make OClass.overrideMe open" "true"
|
||||||
|
|
||||||
|
expect open class OClass() {
|
||||||
|
val overrideMe: String
|
||||||
|
}
|
||||||
|
|
||||||
|
class Another: OClass() {
|
||||||
|
override<caret> val overrideMe = ""
|
||||||
|
}
|
||||||
+9
@@ -0,0 +1,9 @@
|
|||||||
|
// "Make OClass.overrideMe open" "true"
|
||||||
|
|
||||||
|
expect open class OClass() {
|
||||||
|
open val overrideMe: String
|
||||||
|
}
|
||||||
|
|
||||||
|
class Another: OClass() {
|
||||||
|
override val overrideMe = ""
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
actual open class OClass actual constructor() {
|
||||||
|
actual open val overrideMe: String = ""
|
||||||
|
}
|
||||||
+3
@@ -0,0 +1,3 @@
|
|||||||
|
actual open class OClass actual constructor() {
|
||||||
|
actual open val overrideMe: String = ""
|
||||||
|
}
|
||||||
+33
@@ -558,6 +558,39 @@ public class QuickFixMultiModuleTestGenerated extends AbstractQuickFixMultiModul
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("idea/testData/multiModuleQuickFix/makeOverridenMemberOpen")
|
||||||
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
|
public static class MakeOverridenMemberOpen extends AbstractQuickFixMultiModuleTest {
|
||||||
|
private void runTest(String testDataFilePath) throws Exception {
|
||||||
|
KotlinTestUtils.runTest(this::doTest, TargetBackend.ANY, testDataFilePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("actual")
|
||||||
|
public void testActual() throws Exception {
|
||||||
|
runTest("idea/testData/multiModuleQuickFix/makeOverridenMemberOpen/actual/");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testAllFilesPresentInMakeOverridenMemberOpen() throws Exception {
|
||||||
|
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/multiModuleQuickFix/makeOverridenMemberOpen"), Pattern.compile("^([^\\.]+)$"), TargetBackend.ANY, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("expect")
|
||||||
|
public void testExpect() throws Exception {
|
||||||
|
runTest("idea/testData/multiModuleQuickFix/makeOverridenMemberOpen/expect/");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("hasAbstract")
|
||||||
|
public void testHasAbstract() throws Exception {
|
||||||
|
runTest("idea/testData/multiModuleQuickFix/makeOverridenMemberOpen/hasAbstract/");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("hasOpen")
|
||||||
|
public void testHasOpen() throws Exception {
|
||||||
|
runTest("idea/testData/multiModuleQuickFix/makeOverridenMemberOpen/hasOpen/");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("idea/testData/multiModuleQuickFix/other")
|
@TestMetadata("idea/testData/multiModuleQuickFix/other")
|
||||||
@TestDataPath("$PROJECT_ROOT")
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
@RunWith(JUnit3RunnerWithInners.class)
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
|
|||||||
Reference in New Issue
Block a user