From 3c9f0e4775b530f1a1582439b0d9f6d655a7d65d Mon Sep 17 00:00:00 2001 From: Mikhail Glukhikh Date: Wed, 7 Apr 2021 14:04:33 +0300 Subject: [PATCH] Add PrivateInFileEffectiveVisibility language feature (1.6) --- ...irOldFrontendDiagnosticsTestGenerated.java | 6 ++ .../kotlin/resolve/DeclarationsChecker.kt | 2 +- .../resolve/ExposedVisibilityChecker.kt | 13 +++- .../tests/exposed/privateInFile.fir.kt | 2 + .../tests/exposed/privateInFile.kt | 14 ++-- .../exposed/privateInFileDisabled.fir.kt | 30 ++++++++ .../tests/exposed/privateInFileDisabled.kt | 30 ++++++++ .../tests/exposed/privateInFileDisabled.txt | 73 +++++++++++++++++++ .../test/runners/DiagnosticTestGenerated.java | 6 ++ .../kotlin/config/LanguageVersionSettings.kt | 1 + .../idea/quickfix/ChangeVisibilityFix.kt | 6 +- 11 files changed, 172 insertions(+), 11 deletions(-) create mode 100644 compiler/testData/diagnostics/tests/exposed/privateInFileDisabled.fir.kt create mode 100644 compiler/testData/diagnostics/tests/exposed/privateInFileDisabled.kt create mode 100644 compiler/testData/diagnostics/tests/exposed/privateInFileDisabled.txt diff --git a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsTestGenerated.java b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsTestGenerated.java index 9dc2dd6d1ef..47812c2b541 100644 --- a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsTestGenerated.java +++ b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsTestGenerated.java @@ -9281,6 +9281,12 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti runTest("compiler/testData/diagnostics/tests/exposed/privateInFile.kt"); } + @Test + @TestMetadata("privateInFileDisabled.kt") + public void testPrivateInFileDisabled() throws Exception { + runTest("compiler/testData/diagnostics/tests/exposed/privateInFileDisabled.kt"); + } + @Test @TestMetadata("privatePropertyInPrivateConstructor.kt") public void testPrivatePropertyInPrivateConstructor() throws Exception { diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/DeclarationsChecker.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/DeclarationsChecker.kt index 7322a4cb65f..659b692e829 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/DeclarationsChecker.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/DeclarationsChecker.kt @@ -79,7 +79,7 @@ class DeclarationsChecker( private val modifiersChecker = modifiersChecker.withTrace(trace) - private val exposedChecker = ExposedVisibilityChecker(trace) + private val exposedChecker = ExposedVisibilityChecker(languageVersionSettings, trace) private val shadowedExtensionChecker = ShadowedExtensionChecker(typeSpecificityComparator, trace) diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/ExposedVisibilityChecker.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/ExposedVisibilityChecker.kt index 1aaee1c70a0..bc35c3e4453 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/ExposedVisibilityChecker.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/ExposedVisibilityChecker.kt @@ -17,6 +17,8 @@ package org.jetbrains.kotlin.resolve import com.intellij.psi.PsiElement +import org.jetbrains.kotlin.config.LanguageFeature +import org.jetbrains.kotlin.config.LanguageVersionSettings import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.diagnostics.DiagnosticFactory3 import org.jetbrains.kotlin.diagnostics.Errors.* @@ -27,7 +29,10 @@ import org.jetbrains.kotlin.types.isError // Checker for all seven EXPOSED_* errors // All functions return true if everything is OK, or false in case of any errors -class ExposedVisibilityChecker(private val trace: BindingTrace? = null) { +class ExposedVisibilityChecker( + private val languageVersionSettings: LanguageVersionSettings, + private val trace: BindingTrace? = null +) { private fun reportExposure( diagnostic: DiagnosticFactory3, @@ -37,8 +42,10 @@ class ExposedVisibilityChecker(private val trace: BindingTrace? = null) { ) { val trace = trace ?: return val restrictingVisibility = restrictingDescriptor.effectiveVisibility() - if (elementVisibility == EffectiveVisibility.PrivateInFile) { - // Deprecation: condition ^ should be changed to false after 1.6 + + if (!languageVersionSettings.supportsFeature(LanguageFeature.PrivateInFileEffectiveVisibility) && + elementVisibility == EffectiveVisibility.PrivateInFile + ) { trace.report(EXPOSED_FROM_PRIVATE_IN_FILE.on(element, restrictingDescriptor, restrictingVisibility)) } else { trace.report(diagnostic.on(element, elementVisibility, restrictingDescriptor, restrictingVisibility)) diff --git a/compiler/testData/diagnostics/tests/exposed/privateInFile.fir.kt b/compiler/testData/diagnostics/tests/exposed/privateInFile.fir.kt index 15607efc369..173e381c646 100644 --- a/compiler/testData/diagnostics/tests/exposed/privateInFile.fir.kt +++ b/compiler/testData/diagnostics/tests/exposed/privateInFile.fir.kt @@ -1,3 +1,5 @@ +// !LANGUAGE: +PrivateInFileEffectiveVisibility + class Public { private open class NestedPrivate diff --git a/compiler/testData/diagnostics/tests/exposed/privateInFile.kt b/compiler/testData/diagnostics/tests/exposed/privateInFile.kt index 9adec6bf6b7..48fb6d80db7 100644 --- a/compiler/testData/diagnostics/tests/exposed/privateInFile.kt +++ b/compiler/testData/diagnostics/tests/exposed/privateInFile.kt @@ -1,3 +1,5 @@ +// !LANGUAGE: +PrivateInFileEffectiveVisibility + class Public { private open class NestedPrivate @@ -11,17 +13,17 @@ class Public { private class PrivateInFileClass { private open class NestedPrivate - fun test1() = NestedPrivate() - fun test2(p: NestedPrivate) {} - fun NestedPrivate.test3() {} - val test4 = NestedPrivate() - class Test5 : NestedPrivate() + fun test1() = NestedPrivate() + fun test2(p: NestedPrivate) {} + fun NestedPrivate.test3() {} + val test4 = NestedPrivate() + class Test5 : NestedPrivate() } private interface PrivateInFile { private class Private - fun expose() = Private() + fun expose() = Private() } // Exposes 'PrivateInFile$Private' via 'expose' diff --git a/compiler/testData/diagnostics/tests/exposed/privateInFileDisabled.fir.kt b/compiler/testData/diagnostics/tests/exposed/privateInFileDisabled.fir.kt new file mode 100644 index 00000000000..025a5faaf20 --- /dev/null +++ b/compiler/testData/diagnostics/tests/exposed/privateInFileDisabled.fir.kt @@ -0,0 +1,30 @@ +// !LANGUAGE: -PrivateInFileEffectiveVisibility + +class Public { + private open class NestedPrivate + + fun test1() = NestedPrivate() + fun test2(p: NestedPrivate) {} + fun NestedPrivate.test3() {} + val test4 = NestedPrivate() + class Test5 : NestedPrivate() +} + +private class PrivateInFileClass { + private open class NestedPrivate + + fun test1() = NestedPrivate() + fun test2(p: NestedPrivate) {} + fun NestedPrivate.test3() {} + val test4 = NestedPrivate() + class Test5 : NestedPrivate() +} + +private interface PrivateInFile { + private class Private + + fun expose() = Private() +} + +// Exposes 'PrivateInFile$Private' via 'expose' +class Derived : PrivateInFile diff --git a/compiler/testData/diagnostics/tests/exposed/privateInFileDisabled.kt b/compiler/testData/diagnostics/tests/exposed/privateInFileDisabled.kt new file mode 100644 index 00000000000..280086dabcd --- /dev/null +++ b/compiler/testData/diagnostics/tests/exposed/privateInFileDisabled.kt @@ -0,0 +1,30 @@ +// !LANGUAGE: -PrivateInFileEffectiveVisibility + +class Public { + private open class NestedPrivate + + fun test1() = NestedPrivate() + fun test2(p: NestedPrivate) {} + fun NestedPrivate.test3() {} + val test4 = NestedPrivate() + class Test5 : NestedPrivate() +} + +private class PrivateInFileClass { + private open class NestedPrivate + + fun test1() = NestedPrivate() + fun test2(p: NestedPrivate) {} + fun NestedPrivate.test3() {} + val test4 = NestedPrivate() + class Test5 : NestedPrivate() +} + +private interface PrivateInFile { + private class Private + + fun expose() = Private() +} + +// Exposes 'PrivateInFile$Private' via 'expose' +class Derived : PrivateInFile diff --git a/compiler/testData/diagnostics/tests/exposed/privateInFileDisabled.txt b/compiler/testData/diagnostics/tests/exposed/privateInFileDisabled.txt new file mode 100644 index 00000000000..93be0535614 --- /dev/null +++ b/compiler/testData/diagnostics/tests/exposed/privateInFileDisabled.txt @@ -0,0 +1,73 @@ +package + +public final class Derived : PrivateInFile { + public constructor Derived() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun expose(): PrivateInFile.Private + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +private interface PrivateInFile { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open fun expose(): PrivateInFile.Private + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + + private final class Private { + public constructor Private() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + } +} + +private final class PrivateInFileClass { + public constructor PrivateInFileClass() + public final val test4: PrivateInFileClass.NestedPrivate + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public final fun test1(): PrivateInFileClass.NestedPrivate + public final fun test2(/*0*/ p: PrivateInFileClass.NestedPrivate): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + public final fun PrivateInFileClass.NestedPrivate.test3(): kotlin.Unit + + private open class NestedPrivate { + public constructor NestedPrivate() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + } + + public final class Test5 : PrivateInFileClass.NestedPrivate { + public constructor Test5() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + } +} + +public final class Public { + public constructor Public() + public final val test4: Public.NestedPrivate + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public final fun test1(): Public.NestedPrivate + public final fun test2(/*0*/ p: Public.NestedPrivate): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + public final fun Public.NestedPrivate.test3(): kotlin.Unit + + private open class NestedPrivate { + public constructor NestedPrivate() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + } + + public final class Test5 : Public.NestedPrivate { + public constructor Test5() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + } +} diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java index f6b81daddb0..e976c0232c8 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java @@ -9287,6 +9287,12 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest { runTest("compiler/testData/diagnostics/tests/exposed/privateInFile.kt"); } + @Test + @TestMetadata("privateInFileDisabled.kt") + public void testPrivateInFileDisabled() throws Exception { + runTest("compiler/testData/diagnostics/tests/exposed/privateInFileDisabled.kt"); + } + @Test @TestMetadata("privatePropertyInPrivateConstructor.kt") public void testPrivatePropertyInPrivateConstructor() throws Exception { diff --git a/compiler/util/src/org/jetbrains/kotlin/config/LanguageVersionSettings.kt b/compiler/util/src/org/jetbrains/kotlin/config/LanguageVersionSettings.kt index 48ee6d55efc..8acffafb403 100644 --- a/compiler/util/src/org/jetbrains/kotlin/config/LanguageVersionSettings.kt +++ b/compiler/util/src/org/jetbrains/kotlin/config/LanguageVersionSettings.kt @@ -164,6 +164,7 @@ enum class LanguageFeature( */ TypeEnhancementImprovementsInStrictMode(KOTLIN_1_6), ProhibitJvmFieldOnOverrideFromInterfaceInPrimaryConstructor(KOTLIN_1_6, kind = BUG_FIX), + PrivateInFileEffectiveVisibility(KOTLIN_1_6, kind = BUG_FIX), // Temporarily disabled, see KT-27084/KT-22379 SoundSmartcastFromLoopConditionForLoopAssignedVariables(sinceVersion = null, kind = BUG_FIX), diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/ChangeVisibilityFix.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/ChangeVisibilityFix.kt index ece76abde31..e0dc10684eb 100644 --- a/idea/src/org/jetbrains/kotlin/idea/quickfix/ChangeVisibilityFix.kt +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/ChangeVisibilityFix.kt @@ -22,6 +22,7 @@ import org.jetbrains.kotlin.idea.core.canBeProtected import org.jetbrains.kotlin.idea.core.setVisibility import org.jetbrains.kotlin.idea.inspections.RemoveRedundantSetterFix import org.jetbrains.kotlin.idea.inspections.isRedundantSetter +import org.jetbrains.kotlin.idea.project.languageVersionSettings import org.jetbrains.kotlin.idea.search.usagesSearch.descriptor import org.jetbrains.kotlin.idea.util.runOnExpectAndAllActuals import org.jetbrains.kotlin.lexer.KtModifierKeywordToken @@ -106,7 +107,10 @@ open class ChangeVisibilityFix( descriptor: DeclarationDescriptorWithVisibility, targetVisibility: DescriptorVisibility ): IntentionAction? { - if (!ExposedVisibilityChecker().checkDeclarationWithVisibility(declaration, descriptor, targetVisibility)) return null + if (!ExposedVisibilityChecker(declaration.languageVersionSettings).checkDeclarationWithVisibility( + declaration, descriptor, targetVisibility + ) + ) return null val name = descriptor.name.asString()