[kotlin] KTIJ-37402 [EXPLICIT_FIELD_VISIBILITY_MUST_BE_LESS_PERMISSIVE] Provide quick fixes to widen visibility

GitOrigin-RevId: 2ffad8b688c03671a88810e1416f4078d73a5a69
This commit is contained in:
Andrey Cherkasov
2026-02-05 20:28:00 +00:00
committed by intellij-monorepo-bot
parent cf6f501722
commit fdbeb15b4a
16 changed files with 171 additions and 0 deletions
@@ -212,6 +212,17 @@ internal object ChangeVisibilityFixFactories {
)
}
val explicitFieldVisibilityMustBeLessPermissive =
KotlinQuickFixFactory.ModCommandBased { diagnostic: KaFirDiagnostic.ExplicitFieldVisibilityMustBeLessPermissive ->
val property = diagnostic.psi
val propertySymbol = property.symbol
listOfNotNull(
createFixToTargetVisibility(propertySymbol, property, Visibilities.Protected),
createFixToTargetVisibility(propertySymbol, property, Visibilities.Internal),
createFixToTargetVisibility(propertySymbol, property, Visibilities.Public),
)
}
private fun createFixForNoExplicitVisibilityInApiMode(
element: KtDeclaration,
): List<ChangeVisibilityModCommandAction> {
@@ -578,6 +578,7 @@ class KotlinK2QuickFixRegistrar : KotlinQuickFixRegistrar() {
registerFactory(ChangeVisibilityFixFactories.superCallFromPublicInline)
registerFactory(ChangeVisibilityFixFactories.protectedCallFromPublicInlineError)
registerFactory(ChangeVisibilityFixFactories.nonPublicCallFromPublicInline)
registerFactory(ChangeVisibilityFixFactories.explicitFieldVisibilityMustBeLessPermissive)
}
private val other = KtQuickFixesListBuilder.registerPsiQuickFix {
@@ -8908,6 +8908,21 @@ public abstract class HighLevelQuickFixTestGenerated extends AbstractHighLevelQu
KotlinTestUtils.runTest(this::doTest, this, testDataFilePath);
}
@TestMetadata("explicitBackingFieldToInternal.kt")
public void testExplicitBackingFieldToInternal() throws Exception {
runTest("../../../idea/tests/testData/quickfix/increaseVisibility/explicitBackingFieldToInternal.kt");
}
@TestMetadata("explicitBackingFieldToProtected.kt")
public void testExplicitBackingFieldToProtected() throws Exception {
runTest("../../../idea/tests/testData/quickfix/increaseVisibility/explicitBackingFieldToProtected.kt");
}
@TestMetadata("explicitBackingFieldToPublic.kt")
public void testExplicitBackingFieldToPublic() throws Exception {
runTest("../../../idea/tests/testData/quickfix/increaseVisibility/explicitBackingFieldToPublic.kt");
}
@TestMetadata("exposedParameterType.kt")
public void testExposedParameterType() throws Exception {
runTest("../../../idea/tests/testData/quickfix/increaseVisibility/exposedParameterType.kt");
@@ -12,6 +12,8 @@ import com.intellij.openapi.util.TextRange
import com.intellij.psi.util.PsiTreeUtil
import org.jetbrains.kotlin.analysis.api.KaExperimentalApi
import org.jetbrains.kotlin.analysis.api.KaSession
import org.jetbrains.kotlin.analysis.api.components.KaDiagnosticCheckerFilter
import org.jetbrains.kotlin.analysis.api.fir.diagnostics.KaFirDiagnostic
import org.jetbrains.kotlin.analysis.api.symbols.KaCallableSymbol
import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.idea.base.codeInsight.handlers.fixers.range
@@ -130,6 +132,13 @@ sealed class ChangeVisibilityModifierIntention(
@OptIn(KaExperimentalApi::class)
override fun KaSession.prepareContext(element: KtDeclaration): Unit? {
// Skip the visibility-change intention when there is an [EXPLICIT_FIELD_VISIBILITY_MUST_BE_LESS_PERMISSIVE],
// as there are already dedicated quick fixes for that compiler error.
if (element.diagnostics(KaDiagnosticCheckerFilter.ONLY_COMMON_CHECKERS)
.any { it is KaFirDiagnostic.ExplicitFieldVisibilityMustBeLessPermissive }
) {
return null
}
val symbol = element.symbol
@OptIn(KaExperimentalApi::class)
@@ -7381,6 +7381,11 @@ public abstract class K2IntentionTestGenerated extends AbstractK2IntentionTest {
KotlinTestUtils.runTest(this::doTest, this, testDataFilePath);
}
@TestMetadata("explicitFieldVisibilityMustBeLessPermissive.kt")
public void testExplicitFieldVisibilityMustBeLessPermissive() throws Exception {
runTest("../../../idea/tests/testData/intentions/changeVisibility/internal/explicitFieldVisibilityMustBeLessPermissive.kt");
}
@TestMetadata("hasJvmFieldInInterfaceCompanion.kt")
public void testHasJvmFieldInInterfaceCompanion() throws Exception {
runTest("../../../idea/tests/testData/intentions/changeVisibility/internal/hasJvmFieldInInterfaceCompanion.kt");
@@ -7704,6 +7709,11 @@ public abstract class K2IntentionTestGenerated extends AbstractK2IntentionTest {
runTest("../../../idea/tests/testData/intentions/changeVisibility/protected/constructorParameter.kt");
}
@TestMetadata("explicitFieldVisibilityMustBeLessPermissive.kt")
public void testExplicitFieldVisibilityMustBeLessPermissive() throws Exception {
runTest("../../../idea/tests/testData/intentions/changeVisibility/protected/explicitFieldVisibilityMustBeLessPermissive.kt");
}
@TestMetadata("noModifier.kt")
public void testNoModifier() throws Exception {
runTest("../../../idea/tests/testData/intentions/changeVisibility/protected/noModifier.kt");
@@ -7808,6 +7818,11 @@ public abstract class K2IntentionTestGenerated extends AbstractK2IntentionTest {
runTest("../../../idea/tests/testData/intentions/changeVisibility/public/destructuringPropertyException.kt");
}
@TestMetadata("explicitFieldVisibilityMustBeLessPermissive.kt")
public void testExplicitFieldVisibilityMustBeLessPermissive() throws Exception {
runTest("../../../idea/tests/testData/intentions/changeVisibility/public/explicitFieldVisibilityMustBeLessPermissive.kt");
}
@TestMetadata("notForSealedPrimaryConstructor.kt")
public void testNotForSealedPrimaryConstructor() throws Exception {
runTest("../../../idea/tests/testData/intentions/changeVisibility/public/notForSealedPrimaryConstructor.kt");
@@ -3571,6 +3571,11 @@ public abstract class K1IntentionTestGenerated extends AbstractK1IntentionTest {
KotlinTestUtils.runTest(this::doTest, this, testDataFilePath);
}
@TestMetadata("explicitFieldVisibilityMustBeLessPermissive.kt")
public void testExplicitFieldVisibilityMustBeLessPermissive() throws Exception {
runTest("testData/intentions/changeVisibility/internal/explicitFieldVisibilityMustBeLessPermissive.kt");
}
@TestMetadata("hasJvmFieldInInterfaceCompanion.kt")
public void testHasJvmFieldInInterfaceCompanion() throws Exception {
runTest("testData/intentions/changeVisibility/internal/hasJvmFieldInInterfaceCompanion.kt");
@@ -3894,6 +3899,11 @@ public abstract class K1IntentionTestGenerated extends AbstractK1IntentionTest {
runTest("testData/intentions/changeVisibility/protected/constructorParameter.kt");
}
@TestMetadata("explicitFieldVisibilityMustBeLessPermissive.kt")
public void testExplicitFieldVisibilityMustBeLessPermissive() throws Exception {
runTest("testData/intentions/changeVisibility/protected/explicitFieldVisibilityMustBeLessPermissive.kt");
}
@TestMetadata("noModifier.kt")
public void testNoModifier() throws Exception {
runTest("testData/intentions/changeVisibility/protected/noModifier.kt");
@@ -3998,6 +4008,11 @@ public abstract class K1IntentionTestGenerated extends AbstractK1IntentionTest {
runTest("testData/intentions/changeVisibility/public/destructuringPropertyException.kt");
}
@TestMetadata("explicitFieldVisibilityMustBeLessPermissive.kt")
public void testExplicitFieldVisibilityMustBeLessPermissive() throws Exception {
runTest("testData/intentions/changeVisibility/public/explicitFieldVisibilityMustBeLessPermissive.kt");
}
@TestMetadata("notForSealedPrimaryConstructor.kt")
public void testNotForSealedPrimaryConstructor() throws Exception {
runTest("testData/intentions/changeVisibility/public/notForSealedPrimaryConstructor.kt");
@@ -10664,6 +10664,21 @@ public abstract class K1QuickFixTestGenerated extends AbstractK1QuickFixTest {
KotlinTestUtils.runTest(this::doTest, this, testDataFilePath);
}
@TestMetadata("explicitBackingFieldToInternal.kt")
public void testExplicitBackingFieldToInternal() throws Exception {
runTest("testData/quickfix/increaseVisibility/explicitBackingFieldToInternal.kt");
}
@TestMetadata("explicitBackingFieldToProtected.kt")
public void testExplicitBackingFieldToProtected() throws Exception {
runTest("testData/quickfix/increaseVisibility/explicitBackingFieldToProtected.kt");
}
@TestMetadata("explicitBackingFieldToPublic.kt")
public void testExplicitBackingFieldToPublic() throws Exception {
runTest("testData/quickfix/increaseVisibility/explicitBackingFieldToPublic.kt");
}
@TestMetadata("exposedParameterType.kt")
public void testExposedParameterType() throws Exception {
runTest("testData/quickfix/increaseVisibility/exposedParameterType.kt");
@@ -0,0 +1,10 @@
// IS_APPLICABLE: false
// COMPILER_ARGUMENTS: -Xexplicit-backing-fields
// K2_ERROR: Private properties cannot have explicit backing fields.
class A {
pr<caret>ivate val prop: List<Int>
field = mutableListOf()
}
// IGNORE_K1
@@ -0,0 +1,10 @@
// IS_APPLICABLE: false
// COMPILER_ARGUMENTS: -Xexplicit-backing-fields
// K2_ERROR: Private properties cannot have explicit backing fields.
class A {
pri<caret>vate val prop: List<Int>
field = mutableListOf()
}
// IGNORE_K1
@@ -0,0 +1,10 @@
// IS_APPLICABLE: false
// COMPILER_ARGUMENTS: -Xexplicit-backing-fields
// K2_ERROR: Private properties cannot have explicit backing fields.
class A {
pri<caret>vate val prop: List<Int>
field = mutableListOf()
}
// IGNORE_K1
@@ -0,0 +1,10 @@
// "Make 'prop' internal" "true"
// COMPILER_ARGUMENTS: -Xexplicit-backing-fields
class Point {
pri<caret>vate val prop: List<Int>
field = mutableListOf()
}
// IGNORE_K1
// FUS_K2_QUICKFIX_NAME: org.jetbrains.kotlin.idea.k2.codeinsight.fixes.ChangeVisibilityFixFactories$ChangeToInternalModCommandAction
@@ -0,0 +1,10 @@
// "Make 'prop' internal" "true"
// COMPILER_ARGUMENTS: -Xexplicit-backing-fields
class Point {
internal val prop: List<Int>
field = mutableListOf()
}
// IGNORE_K1
// FUS_K2_QUICKFIX_NAME: org.jetbrains.kotlin.idea.k2.codeinsight.fixes.ChangeVisibilityFixFactories$ChangeToInternalModCommandAction
@@ -0,0 +1,10 @@
// "Make 'prop' protected" "true"
// COMPILER_ARGUMENTS: -Xexplicit-backing-fields
open class Point {
pri<caret>vate val prop: List<Int>
field = mutableListOf()
}
// IGNORE_K1
// FUS_K2_QUICKFIX_NAME: org.jetbrains.kotlin.idea.k2.codeinsight.fixes.ChangeVisibilityFixFactories$ChangeToProtectedModCommandAction
@@ -0,0 +1,10 @@
// "Make 'prop' protected" "true"
// COMPILER_ARGUMENTS: -Xexplicit-backing-fields
open class Point {
protected val prop: List<Int>
field = mutableListOf()
}
// IGNORE_K1
// FUS_K2_QUICKFIX_NAME: org.jetbrains.kotlin.idea.k2.codeinsight.fixes.ChangeVisibilityFixFactories$ChangeToProtectedModCommandAction
@@ -0,0 +1,10 @@
// "Make 'prop' public" "true"
// COMPILER_ARGUMENTS: -Xexplicit-backing-fields
class Point {
pri<caret>vate val prop: List<Int>
field = mutableListOf()
}
// IGNORE_K1
// FUS_K2_QUICKFIX_NAME: org.jetbrains.kotlin.idea.k2.codeinsight.fixes.ChangeVisibilityFixFactories$ChangeToPublicModCommandAction
@@ -0,0 +1,10 @@
// "Make 'prop' public" "true"
// COMPILER_ARGUMENTS: -Xexplicit-backing-fields
class Point {
val prop: List<Int>
field = mutableListOf()
}
// IGNORE_K1
// FUS_K2_QUICKFIX_NAME: org.jetbrains.kotlin.idea.k2.codeinsight.fixes.ChangeVisibilityFixFactories$ChangeToPublicModCommandAction