KT-46146 'protected' and 'private' only for sealed constructors

Prior to this commit we suggested two invalid intentions for sealed
class constructors: change visibility to 'public' and 'internal'.

^KT-46146 Fixed
This commit is contained in:
Andrei Klunnyi
2021-05-05 14:49:16 +03:00
committed by Space
parent 686368749a
commit e56a3b3c30
8 changed files with 53 additions and 8 deletions
@@ -14,7 +14,6 @@ import com.intellij.psi.util.PsiTreeUtil
import com.intellij.psi.util.elementType
import org.jetbrains.kotlin.builtins.isFunctionOrSuspendFunctionType
import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.extensions.DeclarationAttributeAltererExtension
import org.jetbrains.kotlin.idea.FrontendInternals
@@ -358,6 +357,8 @@ fun KtModifierListOwner.canBePrivate(): Boolean {
return true
}
fun KtModifierListOwner.canBePublic(): Boolean = !isSealedClassConstructor()
fun KtModifierListOwner.canBeProtected(): Boolean {
val parent = when (this) {
is KtPropertyAccessor -> this.property.parent
@@ -376,12 +377,18 @@ fun KtModifierListOwner.canBeInternal(): Boolean {
val objectDeclaration = getStrictParentOfType<KtObjectDeclaration>() ?: return false
if (objectDeclaration.isCompanion() && hasJvmFieldAnnotation()) return false
}
return !isAnnotationClassPrimaryConstructor()
return !isAnnotationClassPrimaryConstructor() && !isSealedClassConstructor()
}
private fun KtModifierListOwner.isAnnotationClassPrimaryConstructor(): Boolean =
this is KtPrimaryConstructor && (this.parent as? KtClass)?.hasModifier(KtTokens.ANNOTATION_KEYWORD) ?: false
private fun KtModifierListOwner.isSealedClassConstructor(): Boolean {
if (this !is KtConstructor<*>) return false
val ktClass = getContainingClassOrObject().safeAs<KtClass>() ?: return false
return ktClass.isSealed()
}
fun KtClass.isInheritable(): Boolean {
return when (getModalityFromDescriptor()) {
KtTokens.ABSTRACT_KEYWORD, KtTokens.OPEN_KEYWORD, KtTokens.SEALED_KEYWORD -> true
@@ -97,7 +97,10 @@ open class ChangeVisibilityModifierIntention protected constructor(val modifier:
else -> null
}
class Public : ChangeVisibilityModifierIntention(KtTokens.PUBLIC_KEYWORD), HighPriorityAction
class Public : ChangeVisibilityModifierIntention(KtTokens.PUBLIC_KEYWORD), HighPriorityAction {
override fun applicabilityRange(element: KtDeclaration): TextRange? =
if (element.canBePublic()) super.applicabilityRange(element) else null
}
class Private : ChangeVisibilityModifierIntention(KtTokens.PRIVATE_KEYWORD), HighPriorityAction {
override fun applicabilityRange(element: KtDeclaration): TextRange? =
@@ -16,10 +16,7 @@ import org.jetbrains.kotlin.descriptors.DescriptorVisibility
import org.jetbrains.kotlin.diagnostics.Diagnostic
import org.jetbrains.kotlin.diagnostics.DiagnosticFactory0
import org.jetbrains.kotlin.idea.KotlinBundle
import org.jetbrains.kotlin.idea.core.canBeInternal
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.core.*
import org.jetbrains.kotlin.idea.inspections.RemoveRedundantSetterFix
import org.jetbrains.kotlin.idea.inspections.isRedundantSetter
import org.jetbrains.kotlin.idea.project.languageVersionSettings
@@ -62,7 +59,13 @@ open class ChangeVisibilityFix(
}
protected class ChangeToPublicFix(element: KtModifierListOwner, elementName: String) :
ChangeVisibilityFix(element, elementName, KtTokens.PUBLIC_KEYWORD), HighPriorityAction
ChangeVisibilityFix(element, elementName, KtTokens.PUBLIC_KEYWORD), HighPriorityAction {
override fun isAvailable(project: Project, editor: Editor?, file: KtFile): Boolean {
val element = element ?: return false
return element.canBePublic()
}
}
protected class ChangeToProtectedFix(element: KtModifierListOwner, elementName: String) :
ChangeVisibilityFix(element, elementName, KtTokens.PROTECTED_KEYWORD) {
@@ -0,0 +1,2 @@
// IS_APPLICABLE: false
sealed class C <caret>private constructor()
@@ -0,0 +1,4 @@
// IS_APPLICABLE: false
sealed class C {
<caret>private constructor()
}
@@ -0,0 +1,2 @@
// IS_APPLICABLE: false
sealed class C <caret>private constructor()
@@ -0,0 +1,4 @@
// IS_APPLICABLE: false
sealed class C {
<caret>private constructor()
}
@@ -3402,6 +3402,16 @@ public class IntentionTestGenerated extends AbstractIntentionTest {
runTest("idea/testData/intentions/changeVisibility/internal/notForAnnotationClassPrimaryConstructor.kt");
}
@TestMetadata("notForSealedPrimaryConstructor.kt")
public void testNotForSealedPrimaryConstructor() throws Exception {
runTest("idea/testData/intentions/changeVisibility/internal/notForSealedPrimaryConstructor.kt");
}
@TestMetadata("notForSealedSecondaryConstructor.kt")
public void testNotForSealedSecondaryConstructor() throws Exception {
runTest("idea/testData/intentions/changeVisibility/internal/notForSealedSecondaryConstructor.kt");
}
@TestMetadata("propertySetter.kt")
public void testPropertySetter() throws Exception {
runTest("idea/testData/intentions/changeVisibility/internal/propertySetter.kt");
@@ -3726,6 +3736,16 @@ public class IntentionTestGenerated extends AbstractIntentionTest {
runTest("idea/testData/intentions/changeVisibility/public/destructuringPropertyException.kt");
}
@TestMetadata("notForSealedPrimaryConstructor.kt")
public void testNotForSealedPrimaryConstructor() throws Exception {
runTest("idea/testData/intentions/changeVisibility/public/notForSealedPrimaryConstructor.kt");
}
@TestMetadata("notForSealedSecondaryConstructor.kt")
public void testNotForSealedSecondaryConstructor() throws Exception {
runTest("idea/testData/intentions/changeVisibility/public/notForSealedSecondaryConstructor.kt");
}
@TestMetadata("primaryConstructor.kt")
public void testPrimaryConstructor() throws Exception {
runTest("idea/testData/intentions/changeVisibility/public/primaryConstructor.kt");