MakeOverriddenMemberOpenFix: should update actual members

#KT-32586 Fixed
This commit is contained in:
Dmitry Gridin
2019-09-03 15:26:24 +07:00
parent 58d303afcc
commit 650a6e5cc4
19 changed files with 146 additions and 2 deletions
@@ -97,7 +97,7 @@ private fun MemberDescriptor.isConstructorInActual(checkConstructor: Boolean) =
private fun MemberDescriptor.isEnumEntryInActual() =
(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.isExpect) return emptyList()
@@ -13,12 +13,16 @@ import com.intellij.psi.util.CachedValueProvider
import com.intellij.psi.util.PsiModificationTracker
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
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.diagnostics.Diagnostic
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptorIfAny
import org.jetbrains.kotlin.idea.core.util.CachedValue
import org.jetbrains.kotlin.idea.core.util.getValue
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.psi.KtCallableDeclaration
import org.jetbrains.kotlin.psi.KtDeclaration
@@ -56,6 +60,17 @@ class MakeOverriddenMemberOpenFix(declaration: KtDeclaration) : KotlinQuickFixAc
) {
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()
overriddenNonOverridableMembers.add(overriddenMember.createSmartPointer())
containingDeclarationsNames.add(containingDeclarationName)
@@ -69,7 +84,7 @@ class MakeOverriddenMemberOpenFix(declaration: KtDeclaration) : KotlinQuickFixAc
override fun getText(): String {
val element = element ?: return ""
if (overriddenNonOverridableMembers.size == 1) {
if (containingDeclarationsNames.size == 1) {
val name = containingDeclarationsNames[0] + "." + element.name
return "Make $name $OPEN_KEYWORD"
}
@@ -0,0 +1,3 @@
expect open class OClass() {
val overrideMe: String
}
@@ -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 = ""
}
@@ -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 = ""
}
@@ -0,0 +1,9 @@
// "Make OClass.overrideMe open" "true"
expect open class OClass() {
val overrideMe: String
}
class Another: OClass() {
override<caret> val overrideMe = ""
}
@@ -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 = ""
}
@@ -0,0 +1,3 @@
actual open class OClass actual constructor() {
actual open val overrideMe: String = ""
}
@@ -0,0 +1,9 @@
// "Make OClass.overrideMe open" "true"
expect open class OClass() {
val overrideMe: String
}
class Another: OClass() {
override<caret> val overrideMe = ""
}
@@ -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 abstract class OClass actual constructor() {
actual abstract val overrideMe: String
}
@@ -0,0 +1,3 @@
actual abstract class OClass actual constructor() {
actual abstract val overrideMe: String
}
@@ -0,0 +1,9 @@
// "Make OClass.overrideMe open" "true"
expect open class OClass() {
val overrideMe: String
}
class Another: OClass() {
override<caret> val overrideMe = ""
}
@@ -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 = ""
}
@@ -0,0 +1,3 @@
actual open class OClass actual constructor() {
actual open val overrideMe: String = ""
}
@@ -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")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)