[FIR] Explicit API mode: No REDUNDANT_VISIBILITY_MODIFIER for public
- In explicit API mode, the `public` visibility modifier is not redundant unless a declaration is hidden by a container. The `REDUNDANT_VISIBILITY_MODIFIER` diagnostic is now not reported in such cases. ^KTIJ-24485 fixed
This commit is contained in:
committed by
Space Team
parent
5909b191a5
commit
e86c877733
+6
@@ -2741,6 +2741,12 @@ public class DiagnosisCompilerFirTestdataTestGenerated extends AbstractDiagnosis
|
|||||||
runTest("compiler/fir/analysis-tests/testData/resolve/extendedCheckers/RedundantVisibilityModifierCheckerForInnerComponents.kt");
|
runTest("compiler/fir/analysis-tests/testData/resolve/extendedCheckers/RedundantVisibilityModifierCheckerForInnerComponents.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("RedundantVisibilityModifierCheckerWithExplicitApiMode.kt")
|
||||||
|
public void testRedundantVisibilityModifierCheckerWithExplicitApiMode() throws Exception {
|
||||||
|
runTest("compiler/fir/analysis-tests/testData/resolve/extendedCheckers/RedundantVisibilityModifierCheckerWithExplicitApiMode.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Nested
|
@Nested
|
||||||
@TestMetadata("compiler/fir/analysis-tests/testData/resolve/extendedCheckers/canBeReplacedWithOperatorAssignment")
|
@TestMetadata("compiler/fir/analysis-tests/testData/resolve/extendedCheckers/canBeReplacedWithOperatorAssignment")
|
||||||
@TestDataPath("$PROJECT_ROOT")
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
|
|||||||
+5
@@ -2394,6 +2394,11 @@ public class LazyBodyIsNotTouchedTilContractsPhaseTestGenerated extends Abstract
|
|||||||
runTest("compiler/fir/analysis-tests/testData/resolve/extendedCheckers/RedundantVisibilityModifierCheckerForInnerComponents.kt");
|
runTest("compiler/fir/analysis-tests/testData/resolve/extendedCheckers/RedundantVisibilityModifierCheckerForInnerComponents.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("RedundantVisibilityModifierCheckerWithExplicitApiMode.kt")
|
||||||
|
public void testRedundantVisibilityModifierCheckerWithExplicitApiMode() throws Exception {
|
||||||
|
runTest("compiler/fir/analysis-tests/testData/resolve/extendedCheckers/RedundantVisibilityModifierCheckerWithExplicitApiMode.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("compiler/fir/analysis-tests/testData/resolve/extendedCheckers/canBeReplacedWithOperatorAssignment")
|
@TestMetadata("compiler/fir/analysis-tests/testData/resolve/extendedCheckers/canBeReplacedWithOperatorAssignment")
|
||||||
@TestDataPath("$PROJECT_ROOT")
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
@RunWith(JUnit3RunnerWithInners.class)
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
|
|||||||
+190
@@ -0,0 +1,190 @@
|
|||||||
|
FILE: RedundantVisibilityModifierCheckerWithExplicitApiMode.kt
|
||||||
|
public final fun f1(): R|kotlin/Unit| {
|
||||||
|
local final class LocalClass : R|kotlin/Any| {
|
||||||
|
public constructor(): R|LocalClass| {
|
||||||
|
super<R|kotlin/Any|>()
|
||||||
|
}
|
||||||
|
|
||||||
|
public final var foo: R|kotlin/Int| = Int(0)
|
||||||
|
public get(): R|kotlin/Int|
|
||||||
|
public set(value: R|kotlin/Int|): R|kotlin/Unit|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
R|/LocalClass.LocalClass|().R|<local>/foo| = Int(1)
|
||||||
|
}
|
||||||
|
public final fun f2(): R|kotlin/Unit| {
|
||||||
|
R|/f1|()
|
||||||
|
}
|
||||||
|
public final inline fun h1(): R|kotlin/Unit| {
|
||||||
|
R|/f1|()
|
||||||
|
}
|
||||||
|
public final inline fun h2(): R|kotlin/Unit| {
|
||||||
|
R|/f1|()
|
||||||
|
}
|
||||||
|
public final class C1 : R|kotlin/Any| {
|
||||||
|
public constructor(string: R|kotlin/String|): R|C1| {
|
||||||
|
super<R|kotlin/Any|>()
|
||||||
|
}
|
||||||
|
|
||||||
|
public final val foo: R|kotlin/Int| = Int(0)
|
||||||
|
public get(): R|kotlin/Int|
|
||||||
|
|
||||||
|
public final val z: R|kotlin/Any| = object : R|kotlin/Any| {
|
||||||
|
private constructor(): R|<anonymous>| {
|
||||||
|
super<R|kotlin/Any|>()
|
||||||
|
}
|
||||||
|
|
||||||
|
public final fun foo(): R|kotlin/Int| {
|
||||||
|
^foo Int(13)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public get(): R|kotlin/Any|
|
||||||
|
|
||||||
|
public final fun x(): R|kotlin/Unit| {
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
public final class C2 : R|kotlin/Any| {
|
||||||
|
public constructor(string: R|kotlin/String|): R|C2| {
|
||||||
|
super<R|kotlin/Any|>()
|
||||||
|
}
|
||||||
|
|
||||||
|
public final val foo: R|kotlin/Int| = Int(0)
|
||||||
|
public get(): R|kotlin/Int|
|
||||||
|
|
||||||
|
public final val z: R|kotlin/Any| = object : R|kotlin/Any| {
|
||||||
|
private constructor(): R|<anonymous>| {
|
||||||
|
super<R|kotlin/Any|>()
|
||||||
|
}
|
||||||
|
|
||||||
|
public final fun foo(): R|kotlin/Int| {
|
||||||
|
^foo Int(13)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public get(): R|kotlin/Any|
|
||||||
|
|
||||||
|
public final fun x(): R|kotlin/Unit| {
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
public open class D1 : R|kotlin/Any| {
|
||||||
|
public constructor(): R|D1| {
|
||||||
|
super<R|kotlin/Any|>()
|
||||||
|
}
|
||||||
|
|
||||||
|
public open fun willRemainPublic(): R|kotlin/Unit| {
|
||||||
|
}
|
||||||
|
|
||||||
|
protected open fun willBecomePublic(): R|kotlin/Unit| {
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
public open class D2 : R|kotlin/Any| {
|
||||||
|
public constructor(): R|D2| {
|
||||||
|
super<R|kotlin/Any|>()
|
||||||
|
}
|
||||||
|
|
||||||
|
public open fun willRemainPublic(): R|kotlin/Unit| {
|
||||||
|
}
|
||||||
|
|
||||||
|
protected open fun willBecomePublic(): R|kotlin/Unit| {
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
public abstract interface I1 : R|kotlin/Any| {
|
||||||
|
public abstract fun bar(): R|kotlin/Unit|
|
||||||
|
|
||||||
|
}
|
||||||
|
public abstract interface I2 : R|kotlin/Any| {
|
||||||
|
public abstract fun bar(): R|kotlin/Unit|
|
||||||
|
|
||||||
|
}
|
||||||
|
public final var baz1: R|kotlin/Int| = Int(0)
|
||||||
|
public get(): R|kotlin/Int|
|
||||||
|
public set(value: R|kotlin/Int|): R|kotlin/Unit|
|
||||||
|
public final var baz2: R|kotlin/Int| = Int(0)
|
||||||
|
public get(): R|kotlin/Int|
|
||||||
|
public set(value: R|kotlin/Int|): R|kotlin/Unit|
|
||||||
|
public final class J1 : R|kotlin/Any| {
|
||||||
|
public constructor(): R|J1| {
|
||||||
|
super<R|kotlin/Any|>()
|
||||||
|
}
|
||||||
|
|
||||||
|
protected final val baz: R|kotlin/Int| = Int(0)
|
||||||
|
protected get(): R|kotlin/Int| {
|
||||||
|
^ this@R|/J1|.F|/J1.baz|.R|kotlin/Int.times|(Int(2))
|
||||||
|
}
|
||||||
|
|
||||||
|
public final var baf: R|kotlin/Int| = Int(0)
|
||||||
|
public get(): R|kotlin/Int| {
|
||||||
|
^ Int(1)
|
||||||
|
}
|
||||||
|
public set(value: R|kotlin/Int|): R|kotlin/Unit| {
|
||||||
|
this@R|/J1|.F|/J1.baf| = R|<local>/value|
|
||||||
|
}
|
||||||
|
|
||||||
|
public final var buf: R|kotlin/Int| = Int(0)
|
||||||
|
private get(): R|kotlin/Int| {
|
||||||
|
^ Int(42)
|
||||||
|
}
|
||||||
|
protected set(value: R|kotlin/Int|): R|kotlin/Unit| {
|
||||||
|
this@R|/J1|.F|/J1.buf| = R|<local>/value|
|
||||||
|
}
|
||||||
|
|
||||||
|
public final var bar: R|kotlin/Int| = Int(0)
|
||||||
|
public get(): R|kotlin/Int| {
|
||||||
|
^ Double(3.1415926535)
|
||||||
|
}
|
||||||
|
public set(value: R|kotlin/Int|): R|kotlin/Unit| {
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
public final class J2 : R|kotlin/Any| {
|
||||||
|
public constructor(): R|J2| {
|
||||||
|
super<R|kotlin/Any|>()
|
||||||
|
}
|
||||||
|
|
||||||
|
protected final val baz: R|kotlin/Int| = Int(0)
|
||||||
|
protected get(): R|kotlin/Int| {
|
||||||
|
^ this@R|/J2|.F|/J2.baz|.R|kotlin/Int.times|(Int(2))
|
||||||
|
}
|
||||||
|
|
||||||
|
public final var baf: R|kotlin/Int| = Int(0)
|
||||||
|
public get(): R|kotlin/Int| {
|
||||||
|
^ Int(1)
|
||||||
|
}
|
||||||
|
public set(value: R|kotlin/Int|): R|kotlin/Unit| {
|
||||||
|
this@R|/J2|.F|/J2.baf| = R|<local>/value|
|
||||||
|
}
|
||||||
|
|
||||||
|
public final var buf: R|kotlin/Int| = Int(0)
|
||||||
|
private get(): R|kotlin/Int| {
|
||||||
|
^ Int(42)
|
||||||
|
}
|
||||||
|
protected set(value: R|kotlin/Int|): R|kotlin/Unit| {
|
||||||
|
this@R|/J2|.F|/J2.buf| = R|<local>/value|
|
||||||
|
}
|
||||||
|
|
||||||
|
public final var bar: R|kotlin/Int| = Int(0)
|
||||||
|
public get(): R|kotlin/Int| {
|
||||||
|
^ Double(3.1415926535)
|
||||||
|
}
|
||||||
|
public set(value: R|kotlin/Int|): R|kotlin/Unit| {
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
private final class Hidden : R|kotlin/Any| {
|
||||||
|
public constructor(): R|Hidden| {
|
||||||
|
super<R|kotlin/Any|>()
|
||||||
|
}
|
||||||
|
|
||||||
|
public final fun f(): R|kotlin/Int| {
|
||||||
|
^f Int(5)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+116
@@ -0,0 +1,116 @@
|
|||||||
|
// EXPLICIT_API_MODE: STRICT
|
||||||
|
|
||||||
|
fun f1() {
|
||||||
|
class LocalClass {
|
||||||
|
public var foo = 0
|
||||||
|
}
|
||||||
|
LocalClass().foo = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
public fun f2() {
|
||||||
|
f1()
|
||||||
|
}
|
||||||
|
|
||||||
|
<!NO_EXPLICIT_VISIBILITY_IN_API_MODE!><!NOTHING_TO_INLINE!>inline<!> fun h1<!>() {
|
||||||
|
f1()
|
||||||
|
}
|
||||||
|
|
||||||
|
public <!NOTHING_TO_INLINE!>inline<!> fun h2() {
|
||||||
|
f1()
|
||||||
|
}
|
||||||
|
|
||||||
|
<!NO_EXPLICIT_VISIBILITY_IN_API_MODE!>class C1<!> {
|
||||||
|
<!NO_EXPLICIT_VISIBILITY_IN_API_MODE!>constructor<!>(string: String) { }
|
||||||
|
|
||||||
|
<!NO_EXPLICIT_VISIBILITY_IN_API_MODE!>val foo<!>: Int = 0
|
||||||
|
|
||||||
|
<!NO_EXPLICIT_VISIBILITY_IN_API_MODE!>val z<!>: Any = object {
|
||||||
|
fun foo() = 13
|
||||||
|
}
|
||||||
|
|
||||||
|
<!NO_EXPLICIT_VISIBILITY_IN_API_MODE!>fun x<!>() { }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class C2 {
|
||||||
|
public constructor(string: String) { }
|
||||||
|
|
||||||
|
public val foo: Int = 0
|
||||||
|
|
||||||
|
public val <!NO_EXPLICIT_RETURN_TYPE_IN_API_MODE!>z<!> = object {
|
||||||
|
public fun foo() = 13
|
||||||
|
}
|
||||||
|
|
||||||
|
public fun x() { }
|
||||||
|
}
|
||||||
|
|
||||||
|
<!NO_EXPLICIT_VISIBILITY_IN_API_MODE!>open class D1<!> {
|
||||||
|
<!NO_EXPLICIT_VISIBILITY_IN_API_MODE!>open fun willRemainPublic<!>() {
|
||||||
|
}
|
||||||
|
|
||||||
|
protected open fun willBecomePublic() {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public open class D2 {
|
||||||
|
public open fun willRemainPublic() {
|
||||||
|
}
|
||||||
|
|
||||||
|
protected open fun willBecomePublic() {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
<!NO_EXPLICIT_VISIBILITY_IN_API_MODE!>interface I1<!> {
|
||||||
|
<!NO_EXPLICIT_VISIBILITY_IN_API_MODE!>fun bar<!>()
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface I2 {
|
||||||
|
public fun bar()
|
||||||
|
}
|
||||||
|
|
||||||
|
<!NO_EXPLICIT_VISIBILITY_IN_API_MODE!>var baz1<!>: Int = 0
|
||||||
|
|
||||||
|
public var baz2: Int = 0
|
||||||
|
|
||||||
|
class J1 {
|
||||||
|
protected val baz: Int = 0
|
||||||
|
<!REDUNDANT_VISIBILITY_MODIFIER!>protected<!> get() = field * 2
|
||||||
|
<!NO_EXPLICIT_VISIBILITY_IN_API_MODE!>var baf<!>: Int = 0
|
||||||
|
get() = 1
|
||||||
|
set(value) {
|
||||||
|
field = value
|
||||||
|
}
|
||||||
|
|
||||||
|
var buf: Int = 0
|
||||||
|
<!GETTER_VISIBILITY_DIFFERS_FROM_PROPERTY_VISIBILITY!>private<!> get() = 42
|
||||||
|
protected set(value) {
|
||||||
|
field = value
|
||||||
|
}
|
||||||
|
|
||||||
|
<!NO_EXPLICIT_VISIBILITY_IN_API_MODE!>var bar<!>: Int = <!PROPERTY_INITIALIZER_NO_BACKING_FIELD!>0<!>
|
||||||
|
get() = <!RETURN_TYPE_MISMATCH!>3.1415926535<!>
|
||||||
|
set(value) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class J2 {
|
||||||
|
protected val baz: Int = 0
|
||||||
|
<!REDUNDANT_VISIBILITY_MODIFIER!>protected<!> get() = field * 2
|
||||||
|
public var baf: Int = 0
|
||||||
|
public get() = 1
|
||||||
|
public set(value) {
|
||||||
|
field = value
|
||||||
|
}
|
||||||
|
|
||||||
|
public var buf: Int = 0
|
||||||
|
<!GETTER_VISIBILITY_DIFFERS_FROM_PROPERTY_VISIBILITY!>private<!> get() = 42
|
||||||
|
protected set(value) {
|
||||||
|
field = value
|
||||||
|
}
|
||||||
|
|
||||||
|
public var bar: Int = <!PROPERTY_INITIALIZER_NO_BACKING_FIELD!>0<!>
|
||||||
|
get() = <!RETURN_TYPE_MISMATCH!>3.1415926535<!>
|
||||||
|
set(value) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class Hidden {
|
||||||
|
<!REDUNDANT_VISIBILITY_MODIFIER!>public<!> fun f(): Int = 5
|
||||||
|
}
|
||||||
+6
@@ -2741,6 +2741,12 @@ public class FirDiagnosticTestGenerated extends AbstractFirDiagnosticTest {
|
|||||||
runTest("compiler/fir/analysis-tests/testData/resolve/extendedCheckers/RedundantVisibilityModifierCheckerForInnerComponents.kt");
|
runTest("compiler/fir/analysis-tests/testData/resolve/extendedCheckers/RedundantVisibilityModifierCheckerForInnerComponents.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("RedundantVisibilityModifierCheckerWithExplicitApiMode.kt")
|
||||||
|
public void testRedundantVisibilityModifierCheckerWithExplicitApiMode() throws Exception {
|
||||||
|
runTest("compiler/fir/analysis-tests/testData/resolve/extendedCheckers/RedundantVisibilityModifierCheckerWithExplicitApiMode.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Nested
|
@Nested
|
||||||
@TestMetadata("compiler/fir/analysis-tests/testData/resolve/extendedCheckers/canBeReplacedWithOperatorAssignment")
|
@TestMetadata("compiler/fir/analysis-tests/testData/resolve/extendedCheckers/canBeReplacedWithOperatorAssignment")
|
||||||
@TestDataPath("$PROJECT_ROOT")
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
|
|||||||
+6
@@ -2741,6 +2741,12 @@ public class FirDiagnosticsWithLightTreeTestGenerated extends AbstractFirDiagnos
|
|||||||
runTest("compiler/fir/analysis-tests/testData/resolve/extendedCheckers/RedundantVisibilityModifierCheckerForInnerComponents.kt");
|
runTest("compiler/fir/analysis-tests/testData/resolve/extendedCheckers/RedundantVisibilityModifierCheckerForInnerComponents.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("RedundantVisibilityModifierCheckerWithExplicitApiMode.kt")
|
||||||
|
public void testRedundantVisibilityModifierCheckerWithExplicitApiMode() throws Exception {
|
||||||
|
runTest("compiler/fir/analysis-tests/testData/resolve/extendedCheckers/RedundantVisibilityModifierCheckerWithExplicitApiMode.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Nested
|
@Nested
|
||||||
@TestMetadata("compiler/fir/analysis-tests/testData/resolve/extendedCheckers/canBeReplacedWithOperatorAssignment")
|
@TestMetadata("compiler/fir/analysis-tests/testData/resolve/extendedCheckers/canBeReplacedWithOperatorAssignment")
|
||||||
@TestDataPath("$PROJECT_ROOT")
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
|
|||||||
+16
-2
@@ -7,6 +7,8 @@ package org.jetbrains.kotlin.fir.analysis.checkers.extended
|
|||||||
|
|
||||||
import org.jetbrains.kotlin.KtFakeSourceElementKind
|
import org.jetbrains.kotlin.KtFakeSourceElementKind
|
||||||
import org.jetbrains.kotlin.KtSourceElement
|
import org.jetbrains.kotlin.KtSourceElement
|
||||||
|
import org.jetbrains.kotlin.config.AnalysisFlags
|
||||||
|
import org.jetbrains.kotlin.config.ExplicitApiMode
|
||||||
import org.jetbrains.kotlin.descriptors.Visibilities
|
import org.jetbrains.kotlin.descriptors.Visibilities
|
||||||
import org.jetbrains.kotlin.descriptors.Visibility
|
import org.jetbrains.kotlin.descriptors.Visibility
|
||||||
import org.jetbrains.kotlin.diagnostics.DiagnosticReporter
|
import org.jetbrains.kotlin.diagnostics.DiagnosticReporter
|
||||||
@@ -121,11 +123,23 @@ object RedundantVisibilityModifierSyntaxChecker : FirDeclarationSyntaxChecker<Fi
|
|||||||
|
|
||||||
val explicitVisibility = element.source?.explicitVisibility
|
val explicitVisibility = element.source?.explicitVisibility
|
||||||
val isHidden = explicitVisibility.isEffectivelyHiddenBy(containingMemberDeclaration)
|
val isHidden = explicitVisibility.isEffectivelyHiddenBy(containingMemberDeclaration)
|
||||||
|
if (isHidden) {
|
||||||
if (explicitVisibility != implicitVisibility && !isHidden) {
|
reportElement(element, context, reporter)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// In explicit API mode, `public` is explicitly required.
|
||||||
|
val explicitApiMode = context.languageVersionSettings.getFlag(AnalysisFlags.explicitApiMode)
|
||||||
|
if (explicitApiMode != ExplicitApiMode.DISABLED && explicitVisibility == Visibilities.Public) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (explicitVisibility == implicitVisibility) {
|
||||||
|
reportElement(element, context, reporter)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun reportElement(element: FirDeclaration, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||||
reporter.reportOn(element.source, FirErrors.REDUNDANT_VISIBILITY_MODIFIER, context)
|
reporter.reportOn(element.source, FirErrors.REDUNDANT_VISIBILITY_MODIFIER, context)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user