diff --git a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/psiModificationUtils.kt b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/psiModificationUtils.kt index ad45bdb6718..12b42d4935d 100644 --- a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/psiModificationUtils.kt +++ b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/psiModificationUtils.kt @@ -32,6 +32,7 @@ import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.addRemoveModifier.MODIFIERS_ORDER import org.jetbrains.kotlin.psi.psiUtil.* +import org.jetbrains.kotlin.psi.synthetics.findClassDescriptor import org.jetbrains.kotlin.psi.typeRefHelpers.setReceiverTypeReference import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.OverridingUtil @@ -47,6 +48,7 @@ import org.jetbrains.kotlin.types.isError import org.jetbrains.kotlin.types.typeUtil.isTypeParameter import org.jetbrains.kotlin.utils.KotlinExceptionWithAttachments import org.jetbrains.kotlin.utils.SmartList +import org.jetbrains.kotlin.utils.addToStdlib.safeAs fun KtLambdaArgument.moveInsideParentheses(bindingContext: BindingContext): KtCallExpression { val ktExpression = this.getArgumentExpression() @@ -365,9 +367,9 @@ fun KtModifierListOwner.canBeProtected(): Boolean { else -> this.parent } return when (parent) { - is KtClassBody -> parent.parent is KtClass + is KtClassBody -> parent.parent is KtClass && !this.isFinalClassConstructor() is KtParameterList -> parent.parent is KtPrimaryConstructor - is KtClass -> !this.isAnnotationClassPrimaryConstructor() + is KtClass -> !this.isAnnotationClassPrimaryConstructor() && !this.isFinalClassConstructor() else -> false } } @@ -383,6 +385,12 @@ fun KtModifierListOwner.canBeInternal(): Boolean { private fun KtModifierListOwner.isAnnotationClassPrimaryConstructor(): Boolean = this is KtPrimaryConstructor && (this.parent as? KtClass)?.hasModifier(KtTokens.ANNOTATION_KEYWORD) ?: false +private fun KtModifierListOwner.isFinalClassConstructor(): Boolean { + if (this !is KtConstructor<*>) return false + val ktClass = getContainingClassOrObject().safeAs() ?: return false + return ktClass.toDescriptor().safeAs()?.isFinalOrEnum ?: return false +} + private fun KtModifierListOwner.isSealedClassConstructor(): Boolean { if (this !is KtConstructor<*>) return false val ktClass = getContainingClassOrObject().safeAs() ?: return false diff --git a/idea/testData/intentions/changeVisibility/protected/notForFinalClass1.kt b/idea/testData/intentions/changeVisibility/protected/notForFinalClass1.kt new file mode 100644 index 00000000000..fe84b34d151 --- /dev/null +++ b/idea/testData/intentions/changeVisibility/protected/notForFinalClass1.kt @@ -0,0 +1,2 @@ +// IS_APPLICABLE: false +class ImplicitFinalClass public constructor() \ No newline at end of file diff --git a/idea/testData/intentions/changeVisibility/protected/notForFinalClass2.kt b/idea/testData/intentions/changeVisibility/protected/notForFinalClass2.kt new file mode 100644 index 00000000000..45a1bfaf460 --- /dev/null +++ b/idea/testData/intentions/changeVisibility/protected/notForFinalClass2.kt @@ -0,0 +1,2 @@ +// IS_APPLICABLE: false +final class ExplicitFinalClass public constructor() \ No newline at end of file diff --git a/idea/testData/intentions/changeVisibility/protected/notForFinalClass3.kt b/idea/testData/intentions/changeVisibility/protected/notForFinalClass3.kt new file mode 100644 index 00000000000..b0d342562d1 --- /dev/null +++ b/idea/testData/intentions/changeVisibility/protected/notForFinalClass3.kt @@ -0,0 +1,2 @@ +// IS_APPLICABLE: false +data class DataClass(val a: Int) private constructor() \ No newline at end of file diff --git a/idea/testData/intentions/changeVisibility/protected/notForFinalClass4.kt b/idea/testData/intentions/changeVisibility/protected/notForFinalClass4.kt new file mode 100644 index 00000000000..e32fbc33fbf --- /dev/null +++ b/idea/testData/intentions/changeVisibility/protected/notForFinalClass4.kt @@ -0,0 +1,2 @@ +// IS_APPLICABLE: false +inline class InlineClass(val a: Int) private constructor() \ No newline at end of file diff --git a/idea/testData/intentions/changeVisibility/protected/notForFinalClass5.kt b/idea/testData/intentions/changeVisibility/protected/notForFinalClass5.kt new file mode 100644 index 00000000000..3829ad6c575 --- /dev/null +++ b/idea/testData/intentions/changeVisibility/protected/notForFinalClass5.kt @@ -0,0 +1,2 @@ +// IS_APPLICABLE: false +enum class EnumClass(val a: Int) private constructor() \ No newline at end of file diff --git a/idea/testData/intentions/changeVisibility/protected/primaryConstructor.kt b/idea/testData/intentions/changeVisibility/protected/primaryConstructor.kt index 514a4c40dcf..46b43cd2bad 100644 --- a/idea/testData/intentions/changeVisibility/protected/primaryConstructor.kt +++ b/idea/testData/intentions/changeVisibility/protected/primaryConstructor.kt @@ -1 +1 @@ -class RegularClass private constructor() \ No newline at end of file +open class RegularClass private constructor() \ No newline at end of file diff --git a/idea/testData/intentions/changeVisibility/protected/primaryConstructor.kt.after b/idea/testData/intentions/changeVisibility/protected/primaryConstructor.kt.after index afef516563a..728408720ec 100644 --- a/idea/testData/intentions/changeVisibility/protected/primaryConstructor.kt.after +++ b/idea/testData/intentions/changeVisibility/protected/primaryConstructor.kt.after @@ -1 +1 @@ -class RegularClass protected constructor() \ No newline at end of file +open class RegularClass protected constructor() \ No newline at end of file diff --git a/idea/testData/quickfix/removeUnused/secondaryConstructorFromJava.before.Main.kt b/idea/testData/quickfix/removeUnused/secondaryConstructorFromJava.before.Main.kt index ec8a96e15a4..1272d05e4b8 100644 --- a/idea/testData/quickfix/removeUnused/secondaryConstructorFromJava.before.Main.kt +++ b/idea/testData/quickfix/removeUnused/secondaryConstructorFromJava.before.Main.kt @@ -2,7 +2,6 @@ // ACTION: Convert to primary constructor // ACTION: Make internal // ACTION: Make private -// ACTION: Make protected class Ctor { constructor(p: Int) diff --git a/idea/testData/quickfix/removeUnused/unusedDelegatedConstructor.kt b/idea/testData/quickfix/removeUnused/unusedDelegatedConstructor.kt index 31901e73c5a..176df48cdb6 100644 --- a/idea/testData/quickfix/removeUnused/unusedDelegatedConstructor.kt +++ b/idea/testData/quickfix/removeUnused/unusedDelegatedConstructor.kt @@ -2,7 +2,6 @@ // ACTION: Convert to primary constructor // ACTION: Make internal // ACTION: Make private -// ACTION: Make protected class CtorUsedByOtherCtor { constructor() diff --git a/idea/testData/quickfix/specifyOverrideExplicitly/notPossible.kt b/idea/testData/quickfix/specifyOverrideExplicitly/notPossible.kt index 045e0c8068c..589615d218b 100644 --- a/idea/testData/quickfix/specifyOverrideExplicitly/notPossible.kt +++ b/idea/testData/quickfix/specifyOverrideExplicitly/notPossible.kt @@ -2,7 +2,6 @@ // ACTION: Create test // ACTION: Make primary constructor internal // ACTION: Make primary constructor private -// ACTION: Make primary constructor protected // ACTION: Enable a trailing comma by default in the formatter // ACTION: Extract 'C' from current file // ACTION: Rename file to C.kt diff --git a/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionTestGenerated.java index b17f732cc38..0b4dbd46a58 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionTestGenerated.java @@ -3673,6 +3673,31 @@ public class IntentionTestGenerated extends AbstractIntentionTest { runTest("idea/testData/intentions/changeVisibility/protected/notForAnnotationPrimaryConstructor.kt"); } + @TestMetadata("notForFinalClass1.kt") + public void testNotForFinalClass1() throws Exception { + runTest("idea/testData/intentions/changeVisibility/protected/notForFinalClass1.kt"); + } + + @TestMetadata("notForFinalClass2.kt") + public void testNotForFinalClass2() throws Exception { + runTest("idea/testData/intentions/changeVisibility/protected/notForFinalClass2.kt"); + } + + @TestMetadata("notForFinalClass3.kt") + public void testNotForFinalClass3() throws Exception { + runTest("idea/testData/intentions/changeVisibility/protected/notForFinalClass3.kt"); + } + + @TestMetadata("notForFinalClass4.kt") + public void testNotForFinalClass4() throws Exception { + runTest("idea/testData/intentions/changeVisibility/protected/notForFinalClass4.kt"); + } + + @TestMetadata("notForFinalClass5.kt") + public void testNotForFinalClass5() throws Exception { + runTest("idea/testData/intentions/changeVisibility/protected/notForFinalClass5.kt"); + } + @TestMetadata("notForNonValParameter.kt") public void testNotForNonValParameter() throws Exception { runTest("idea/testData/intentions/changeVisibility/protected/notForNonValParameter.kt");