Add modality/visibility/inline to all expect/actual declarations in QF
So #KT-25539 Fixed
This commit is contained in:
@@ -12,6 +12,7 @@ import org.jetbrains.kotlin.idea.caches.project.ModuleSourceInfo
|
||||
import org.jetbrains.kotlin.idea.caches.project.implementedDescriptors
|
||||
import org.jetbrains.kotlin.idea.caches.project.implementingDescriptors
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptorIfAny
|
||||
import org.jetbrains.kotlin.idea.core.setVisibility
|
||||
import org.jetbrains.kotlin.idea.core.toDescriptor
|
||||
import org.jetbrains.kotlin.idea.search.usagesSearch.descriptor
|
||||
import org.jetbrains.kotlin.psi.KtClassOrObject
|
||||
@@ -126,3 +127,17 @@ fun KtDeclaration.isEffectivelyActual(): Boolean {
|
||||
|
||||
private fun MemberDescriptor.isEnumEntryInActual() =
|
||||
(DescriptorUtils.isEnumEntry(this) && (containingDeclaration as? MemberDescriptor)?.isActual == true)
|
||||
|
||||
fun KtDeclaration.runOnExpectAndAllActuals(checkExpect: Boolean = true, f: (KtDeclaration) -> Unit) {
|
||||
if (hasActualModifier()) {
|
||||
val expectElement = liftToExpected()
|
||||
expectElement?.actualsForExpected()?.forEach {
|
||||
if (it !== this) {
|
||||
f(it)
|
||||
}
|
||||
}
|
||||
expectElement?.let { f(it) }
|
||||
} else if (!checkExpect || isExpectDeclaration()) {
|
||||
actualsForExpected().forEach { f(it) }
|
||||
}
|
||||
}
|
||||
@@ -30,6 +30,7 @@ import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptorIfAny
|
||||
import org.jetbrains.kotlin.idea.core.quickfix.QuickFixUtil
|
||||
import org.jetbrains.kotlin.idea.inspections.KotlinUniversalQuickFix
|
||||
import org.jetbrains.kotlin.idea.refactoring.canRefactor
|
||||
import org.jetbrains.kotlin.idea.util.runOnExpectAndAllActuals
|
||||
import org.jetbrains.kotlin.lexer.KtModifierKeywordToken
|
||||
import org.jetbrains.kotlin.lexer.KtTokens
|
||||
import org.jetbrains.kotlin.lexer.KtTokens.*
|
||||
@@ -55,11 +56,11 @@ open class AddModifierFix(
|
||||
|
||||
override fun getFamilyName() = "Add modifier"
|
||||
|
||||
override fun invoke(project: Project, editor: Editor?, file: KtFile) {
|
||||
private fun invokeOnElement(element: KtModifierListOwner?) {
|
||||
element?.addModifier(modifier)
|
||||
|
||||
if (modifier == KtTokens.ABSTRACT_KEYWORD && (element is KtProperty || element is KtNamedFunction)) {
|
||||
element?.containingClass()?.run {
|
||||
element.containingClass()?.run {
|
||||
if (!hasModifier(KtTokens.ABSTRACT_KEYWORD) && !hasModifier(KtTokens.SEALED_KEYWORD)) {
|
||||
addModifier(KtTokens.ABSTRACT_KEYWORD)
|
||||
}
|
||||
@@ -67,12 +68,24 @@ open class AddModifierFix(
|
||||
}
|
||||
}
|
||||
|
||||
override fun invoke(project: Project, editor: Editor?, file: KtFile) {
|
||||
val originalElement = element
|
||||
if (originalElement is KtDeclaration && modifier.isMultiplatformPersistent()) {
|
||||
originalElement.runOnExpectAndAllActuals { invokeOnElement(it) }
|
||||
}
|
||||
invokeOnElement(originalElement)
|
||||
}
|
||||
|
||||
override fun isAvailable(project: Project, editor: Editor?, file: KtFile): Boolean {
|
||||
val element = element ?: return false
|
||||
return element.canRefactor()
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
private fun KtModifierKeywordToken.isMultiplatformPersistent(): Boolean =
|
||||
this in KtTokens.MODALITY_MODIFIERS || this == KtTokens.INLINE_KEYWORD
|
||||
|
||||
private val modalityModifiers = setOf(ABSTRACT_KEYWORD, OPEN_KEYWORD, FINAL_KEYWORD)
|
||||
|
||||
fun getElementName(modifierListOwner: KtModifierListOwner): String {
|
||||
|
||||
@@ -26,8 +26,10 @@ import org.jetbrains.kotlin.descriptors.Visibility
|
||||
import org.jetbrains.kotlin.idea.core.canBePrivate
|
||||
import org.jetbrains.kotlin.idea.core.canBeProtected
|
||||
import org.jetbrains.kotlin.idea.core.setVisibility
|
||||
import org.jetbrains.kotlin.idea.util.runOnExpectAndAllActuals
|
||||
import org.jetbrains.kotlin.lexer.KtModifierKeywordToken
|
||||
import org.jetbrains.kotlin.lexer.KtTokens
|
||||
import org.jetbrains.kotlin.psi.KtDeclaration
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.psi.KtModifierListOwner
|
||||
import org.jetbrains.kotlin.resolve.ExposedVisibilityChecker
|
||||
@@ -42,6 +44,11 @@ open class ChangeVisibilityFix(
|
||||
override fun getFamilyName() = "Make $visibilityModifier"
|
||||
|
||||
override fun invoke(project: Project, editor: Editor?, file: KtFile) {
|
||||
val originalElement = element
|
||||
if (originalElement is KtDeclaration) {
|
||||
originalElement.runOnExpectAndAllActuals { it.setVisibility(visibilityModifier) }
|
||||
}
|
||||
|
||||
element?.setVisibility(visibilityModifier)
|
||||
}
|
||||
|
||||
|
||||
+2
-14
@@ -53,9 +53,9 @@ import org.jetbrains.kotlin.idea.search.ideaExtensions.KotlinReferencesSearchOpt
|
||||
import org.jetbrains.kotlin.idea.search.ideaExtensions.KotlinReferencesSearchParameters
|
||||
import org.jetbrains.kotlin.idea.search.projectScope
|
||||
import org.jetbrains.kotlin.idea.search.usagesSearch.processDelegationCallConstructorUsages
|
||||
import org.jetbrains.kotlin.idea.util.actualsForExpected
|
||||
import org.jetbrains.kotlin.idea.util.isExpectDeclaration
|
||||
import org.jetbrains.kotlin.idea.util.liftToExpected
|
||||
import org.jetbrains.kotlin.idea.util.runOnExpectAndAllActuals
|
||||
import org.jetbrains.kotlin.lexer.KtTokens
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.*
|
||||
@@ -400,19 +400,7 @@ class KotlinSafeDeleteProcessor : JavaSafeDeleteProcessor() {
|
||||
|
||||
override fun prepareForDeletion(element: PsiElement) {
|
||||
if (element is KtDeclaration) {
|
||||
if (element.hasActualModifier()) {
|
||||
val expectElement = element.liftToExpected()
|
||||
expectElement?.actualsForExpected()?.forEach {
|
||||
if (it !== element) {
|
||||
it.removeOrClean()
|
||||
}
|
||||
}
|
||||
expectElement?.removeOrClean()
|
||||
} else {
|
||||
element.actualsForExpected().forEach {
|
||||
it.removeOrClean()
|
||||
}
|
||||
}
|
||||
element.runOnExpectAndAllActuals(checkExpect = false) { it.removeOrClean() }
|
||||
}
|
||||
|
||||
when (element) {
|
||||
|
||||
+2
-14
@@ -51,9 +51,9 @@ import org.jetbrains.kotlin.idea.search.ideaExtensions.KotlinReferencesSearchOpt
|
||||
import org.jetbrains.kotlin.idea.search.ideaExtensions.KotlinReferencesSearchParameters
|
||||
import org.jetbrains.kotlin.idea.search.projectScope
|
||||
import org.jetbrains.kotlin.idea.search.usagesSearch.processDelegationCallConstructorUsages
|
||||
import org.jetbrains.kotlin.idea.util.actualsForExpected
|
||||
import org.jetbrains.kotlin.idea.util.isExpectDeclaration
|
||||
import org.jetbrains.kotlin.idea.util.liftToExpected
|
||||
import org.jetbrains.kotlin.idea.util.runOnExpectAndAllActuals
|
||||
import org.jetbrains.kotlin.lexer.KtTokens
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType
|
||||
@@ -392,19 +392,7 @@ class KotlinSafeDeleteProcessor : JavaSafeDeleteProcessor() {
|
||||
|
||||
override fun prepareForDeletion(element: PsiElement) {
|
||||
if (element is KtDeclaration) {
|
||||
if (element.hasActualModifier()) {
|
||||
val expectElement = element.liftToExpected()
|
||||
expectElement?.actualsForExpected()?.forEach {
|
||||
if (it !== element) {
|
||||
it.removeOrClean()
|
||||
}
|
||||
}
|
||||
expectElement?.removeOrClean()
|
||||
} else {
|
||||
element.actualsForExpected().forEach {
|
||||
it.removeOrClean()
|
||||
}
|
||||
}
|
||||
element.runOnExpectAndAllActuals(checkExpect = false) { it.removeOrClean() }
|
||||
}
|
||||
|
||||
when (element) {
|
||||
|
||||
+2
-14
@@ -53,9 +53,9 @@ import org.jetbrains.kotlin.idea.search.ideaExtensions.KotlinReferencesSearchOpt
|
||||
import org.jetbrains.kotlin.idea.search.ideaExtensions.KotlinReferencesSearchParameters
|
||||
import org.jetbrains.kotlin.idea.search.projectScope
|
||||
import org.jetbrains.kotlin.idea.search.usagesSearch.processDelegationCallConstructorUsages
|
||||
import org.jetbrains.kotlin.idea.util.actualsForExpected
|
||||
import org.jetbrains.kotlin.idea.util.isExpectDeclaration
|
||||
import org.jetbrains.kotlin.idea.util.liftToExpected
|
||||
import org.jetbrains.kotlin.idea.util.runOnExpectAndAllActuals
|
||||
import org.jetbrains.kotlin.lexer.KtTokens
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType
|
||||
@@ -402,19 +402,7 @@ class KotlinSafeDeleteProcessor : JavaSafeDeleteProcessor() {
|
||||
|
||||
override fun prepareForDeletion(element: PsiElement) {
|
||||
if (element is KtDeclaration) {
|
||||
if (element.hasActualModifier()) {
|
||||
val expectElement = element.liftToExpected()
|
||||
expectElement?.actualsForExpected()?.forEach {
|
||||
if (it !== element) {
|
||||
it.removeOrClean()
|
||||
}
|
||||
}
|
||||
expectElement?.removeOrClean()
|
||||
} else {
|
||||
element.actualsForExpected().forEach {
|
||||
it.removeOrClean()
|
||||
}
|
||||
}
|
||||
element.runOnExpectAndAllActuals(checkExpect = false) { it.removeOrClean() }
|
||||
}
|
||||
|
||||
when (element) {
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
// "Add 'inline' modifier" "true"
|
||||
// ERROR: Only type parameters of inline functions can be reified
|
||||
|
||||
expect fun <reif<caret>ied T> inlineFun(t: T)
|
||||
@@ -0,0 +1,4 @@
|
||||
// "Add 'inline' modifier" "true"
|
||||
// ERROR: Only type parameters of inline functions can be reified
|
||||
|
||||
expect inline fun <reified T> inlineFun(t: T)
|
||||
@@ -0,0 +1 @@
|
||||
actual fun <reified T> inlineFun(t: T) {}
|
||||
@@ -0,0 +1 @@
|
||||
actual inline fun <reified T> inlineFun(t: T) {}
|
||||
@@ -0,0 +1,6 @@
|
||||
// "Make 'getInternal' internal" "true"
|
||||
// ERROR: 'public' function exposes its 'internal' return type Internal
|
||||
|
||||
internal expect class Internal
|
||||
|
||||
expect fun <caret>getInternal(): Internal
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
// "Make 'getInternal' internal" "true"
|
||||
// ERROR: 'public' function exposes its 'internal' return type Internal
|
||||
|
||||
internal expect class Internal
|
||||
|
||||
internal expect fun getInternal(): Internal
|
||||
@@ -0,0 +1,5 @@
|
||||
internal actual class Internal
|
||||
|
||||
actual fun getInternal(): Internal {
|
||||
return Internal()
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
internal actual class Internal
|
||||
|
||||
internal actual fun getInternal(): Internal {
|
||||
return Internal()
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
expect class One
|
||||
@@ -0,0 +1 @@
|
||||
expect open class One
|
||||
@@ -0,0 +1,5 @@
|
||||
// "Make 'One' open" "true"
|
||||
// ERROR: This type is final, so it cannot be inherited from
|
||||
|
||||
actual class One
|
||||
class Two : <caret>One()
|
||||
@@ -0,0 +1,5 @@
|
||||
// "Make 'One' open" "true"
|
||||
// ERROR: This type is final, so it cannot be inherited from
|
||||
|
||||
actual open class One
|
||||
class Two : <caret>One()
|
||||
@@ -0,0 +1,5 @@
|
||||
// "Make 'One' open" "true"
|
||||
// ERROR: This type is final, so it cannot be inherited from
|
||||
|
||||
expect class One
|
||||
expect class Two : <caret>One
|
||||
@@ -0,0 +1,5 @@
|
||||
// "Make 'One' open" "true"
|
||||
// ERROR: This type is final, so it cannot be inherited from
|
||||
|
||||
expect open class One
|
||||
expect class Two : <caret>One
|
||||
@@ -0,0 +1 @@
|
||||
actual class One
|
||||
@@ -0,0 +1 @@
|
||||
actual open class One
|
||||
+20
@@ -274,6 +274,26 @@ public class QuickFixMultiModuleTestGenerated extends AbstractQuickFixMultiModul
|
||||
runTest("idea/testData/multiModuleQuickFix/interface/");
|
||||
}
|
||||
|
||||
@TestMetadata("makeInlineFromExpect")
|
||||
public void testMakeInlineFromExpect() throws Exception {
|
||||
runTest("idea/testData/multiModuleQuickFix/makeInlineFromExpect/");
|
||||
}
|
||||
|
||||
@TestMetadata("makeInternalFromExpect")
|
||||
public void testMakeInternalFromExpect() throws Exception {
|
||||
runTest("idea/testData/multiModuleQuickFix/makeInternalFromExpect/");
|
||||
}
|
||||
|
||||
@TestMetadata("makeOpenFromActual")
|
||||
public void testMakeOpenFromActual() throws Exception {
|
||||
runTest("idea/testData/multiModuleQuickFix/makeOpenFromActual/");
|
||||
}
|
||||
|
||||
@TestMetadata("makeOpenFromExpect")
|
||||
public void testMakeOpenFromExpect() throws Exception {
|
||||
runTest("idea/testData/multiModuleQuickFix/makeOpenFromExpect/");
|
||||
}
|
||||
|
||||
@TestMetadata("memberFunParameterToReceiverByHeader")
|
||||
public void testMemberFunParameterToReceiverByHeader() throws Exception {
|
||||
runTest("idea/testData/multiModuleQuickFix/memberFunParameterToReceiverByHeader/");
|
||||
|
||||
Reference in New Issue
Block a user