FIR: Handle visibility of public setter of protected synthetic property like in K1

K1 allows writing access to a public setter of a protected synthetic
property only if the call is inside a subclass. K2 previously allowed
that unconditionally. This changes brings the behavior in line with K1.

^KT-56050 Fixed
This commit is contained in:
Kirill Rakhman
2023-01-24 15:38:52 +01:00
committed by Space Team
parent 1990883bdc
commit f6c189be7b
5 changed files with 254 additions and 18 deletions
@@ -9,6 +9,7 @@ import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.descriptors.Visibility import org.jetbrains.kotlin.descriptors.Visibility
import org.jetbrains.kotlin.descriptors.java.JavaVisibilities import org.jetbrains.kotlin.descriptors.java.JavaVisibilities
import org.jetbrains.kotlin.fir.* import org.jetbrains.kotlin.fir.*
import org.jetbrains.kotlin.fir.declarations.FirClass
import org.jetbrains.kotlin.fir.declarations.FirDeclaration import org.jetbrains.kotlin.fir.declarations.FirDeclaration
import org.jetbrains.kotlin.fir.declarations.FirFile import org.jetbrains.kotlin.fir.declarations.FirFile
import org.jetbrains.kotlin.fir.declarations.synthetic.FirSyntheticPropertyAccessor import org.jetbrains.kotlin.fir.declarations.synthetic.FirSyntheticPropertyAccessor
@@ -16,8 +17,10 @@ import org.jetbrains.kotlin.fir.declarations.utils.visibility
import org.jetbrains.kotlin.fir.resolve.SupertypeSupplier import org.jetbrains.kotlin.fir.resolve.SupertypeSupplier
import org.jetbrains.kotlin.fir.resolve.calls.FirSimpleSyntheticPropertySymbol import org.jetbrains.kotlin.fir.resolve.calls.FirSimpleSyntheticPropertySymbol
import org.jetbrains.kotlin.fir.resolve.calls.ReceiverValue import org.jetbrains.kotlin.fir.resolve.calls.ReceiverValue
import org.jetbrains.kotlin.fir.resolve.isSubclassOf
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.utils.addToStdlib.lastIsInstanceOrNull
@NoMutableState @NoMutableState
object FirJavaVisibilityChecker : FirVisibilityChecker() { object FirJavaVisibilityChecker : FirVisibilityChecker() {
@@ -47,7 +50,7 @@ object FirJavaVisibilityChecker : FirVisibilityChecker() {
// FE1.0 allows calling public setters with property assignment syntax if the getter is protected. // FE1.0 allows calling public setters with property assignment syntax if the getter is protected.
if (!isCallToPropertySetter || symbol !is FirSimpleSyntheticPropertySymbol) return false if (!isCallToPropertySetter || symbol !is FirSimpleSyntheticPropertySymbol) return false
symbol.setterSymbol?.visibility == Visibilities.Public symbol.setterSymbol?.visibility == Visibilities.Public && symbol.isCalledFromSubclass(containingDeclarations, session)
} }
} }
@@ -56,6 +59,14 @@ object FirJavaVisibilityChecker : FirVisibilityChecker() {
} }
} }
private fun FirSimpleSyntheticPropertySymbol.isCalledFromSubclass(
containingDeclarations: List<FirDeclaration>,
session: FirSession
): Boolean {
val containingClassLookupTag = this.containingClassLookupTag() ?: return false
return containingDeclarations.any { it is FirClass && it.isSubclassOf(containingClassLookupTag, session, false) }
}
override fun platformOverrideVisibilityCheck( override fun platformOverrideVisibilityCheck(
candidateInDerivedClass: FirBasedSymbol<*>, candidateInDerivedClass: FirBasedSymbol<*>,
symbolInBaseClass: FirBasedSymbol<*>, symbolInBaseClass: FirBasedSymbol<*>,
@@ -1,9 +1,9 @@
// FILE: j/Super.java // FILE: j/Super.java
package j package j
public abstract class Super { public class Super {
protected abstract String getName(); protected String getName() { return "" };
public abstract void setName(String s); public void setName(String s) { }
} }
// FILE: k/test.kt // FILE: k/test.kt
@@ -11,20 +11,110 @@ public abstract class Super {
package k package k
import j.Super import j.Super
abstract class Sub: Super() { abstract class Sub : Super() {
fun test(s: Super) { fun test(s: Super) {
s.<!INVISIBLE_REFERENCE!>name<!> s.<!INVISIBLE_REFERENCE!>name<!>
s.<!INVISIBLE_REFERENCE!>getName<!>() s.<!INVISIBLE_REFERENCE!>getName<!>()
s.name = "" s.name = ""
s.name = s.<!INVISIBLE_REFERENCE!>name<!> s.name = s.<!INVISIBLE_REFERENCE!>name<!>
s.setName("") s.setName("")
val anon1 = object : Super() {
fun testAnon() {
s.<!INVISIBLE_REFERENCE!>name<!>
s.<!INVISIBLE_REFERENCE!>getName<!>()
s.name = ""
s.name = s.<!INVISIBLE_REFERENCE!>name<!>
s.setName("")
}
}
val anon2 = object {
fun testAnon() {
s.<!INVISIBLE_REFERENCE!>name<!>
s.<!INVISIBLE_REFERENCE!>getName<!>()
s.name = ""
s.name = s.<!INVISIBLE_REFERENCE!>name<!>
s.setName("")
}
}
}
inner class Nested1 : Super() {
fun test(s: Super) {
s.<!INVISIBLE_REFERENCE!>name<!>
s.<!INVISIBLE_REFERENCE!>getName<!>()
s.name = ""
s.name = s.<!INVISIBLE_REFERENCE!>name<!>
s.setName("")
}
}
class Nested2 {
fun test(s: Super) {
s.<!INVISIBLE_REFERENCE!>name<!>
s.<!INVISIBLE_REFERENCE!>getName<!>()
s.name = ""
s.name = s.<!INVISIBLE_REFERENCE!>name<!>
s.setName("")
}
}
}
abstract class NonSub {
fun test(s: Super) {
s.<!INVISIBLE_REFERENCE!>name<!>
s.<!INVISIBLE_REFERENCE!>getName<!>()
s.<!INVISIBLE_REFERENCE!>name<!> = ""
s.<!INVISIBLE_REFERENCE!>name<!> = s.<!INVISIBLE_REFERENCE!>name<!>
s.setName("")
val anon1 = object : Super() {
fun testAnon() {
s.<!INVISIBLE_REFERENCE!>name<!>
s.<!INVISIBLE_REFERENCE!>getName<!>()
s.name = ""
s.name = s.<!INVISIBLE_REFERENCE!>name<!>
s.setName("")
}
}
val anon2 = object {
fun testAnon() {
s.<!INVISIBLE_REFERENCE!>name<!>
s.<!INVISIBLE_REFERENCE!>getName<!>()
s.<!INVISIBLE_REFERENCE!>name<!> = ""
s.<!INVISIBLE_REFERENCE!>name<!> = s.<!INVISIBLE_REFERENCE!>name<!>
s.setName("")
}
}
}
inner class Nested1 : Super() {
fun test(s: Super) {
s.<!INVISIBLE_REFERENCE!>name<!>
s.<!INVISIBLE_REFERENCE!>getName<!>()
s.name = ""
s.name = s.<!INVISIBLE_REFERENCE!>name<!>
s.setName("")
}
}
class Nested2 {
fun test(s: Super) {
s.<!INVISIBLE_REFERENCE!>name<!>
s.<!INVISIBLE_REFERENCE!>getName<!>()
s.<!INVISIBLE_REFERENCE!>name<!> = ""
s.<!INVISIBLE_REFERENCE!>name<!> = s.<!INVISIBLE_REFERENCE!>name<!>
s.setName("")
}
} }
} }
fun test(s: Super) { fun test(s: Super) {
s.<!INVISIBLE_REFERENCE!>name<!> s.<!INVISIBLE_REFERENCE!>name<!>
s.<!INVISIBLE_REFERENCE!>getName<!>() s.<!INVISIBLE_REFERENCE!>getName<!>()
s.name = "" s.<!INVISIBLE_REFERENCE!>name<!> = ""
s.name = s.<!INVISIBLE_REFERENCE!>name<!> s.<!INVISIBLE_REFERENCE!>name<!> = s.<!INVISIBLE_REFERENCE!>name<!>
s.setName("") s.setName("")
} }
@@ -1,9 +1,9 @@
// FILE: j/Super.java // FILE: j/Super.java
package j package j
public abstract class Super { public class Super {
protected abstract String getName(); protected String getName() { return "" };
public abstract void setName(String s); public void setName(String s) { }
} }
// FILE: k/test.kt // FILE: k/test.kt
@@ -11,13 +11,103 @@ public abstract class Super {
package k package k
import j.Super import j.Super
abstract class Sub: Super() { abstract class Sub : Super() {
fun test(s: Super) { fun test(s: Super) {
s.<!INVISIBLE_MEMBER!>name<!> s.<!INVISIBLE_MEMBER!>name<!>
s.<!INVISIBLE_MEMBER!>getName<!>() s.<!INVISIBLE_MEMBER!>getName<!>()
s.name = "" s.name = ""
s.name = s.<!INVISIBLE_MEMBER!>name<!> s.name = s.<!INVISIBLE_MEMBER!>name<!>
s.setName("") s.setName("")
val anon1 = object : Super() {
fun testAnon() {
s.<!INVISIBLE_MEMBER!>name<!>
s.<!INVISIBLE_MEMBER!>getName<!>()
s.name = ""
s.name = s.<!INVISIBLE_MEMBER!>name<!>
s.setName("")
}
}
val anon2 = object {
fun testAnon() {
s.<!INVISIBLE_MEMBER!>name<!>
s.<!INVISIBLE_MEMBER!>getName<!>()
s.name = ""
s.name = s.<!INVISIBLE_MEMBER!>name<!>
s.setName("")
}
}
}
inner class Nested1 : Super() {
fun test(s: Super) {
s.<!INVISIBLE_MEMBER!>name<!>
s.<!INVISIBLE_MEMBER!>getName<!>()
s.name = ""
s.name = s.<!INVISIBLE_MEMBER!>name<!>
s.setName("")
}
}
class Nested2 {
fun test(s: Super) {
s.<!INVISIBLE_MEMBER!>name<!>
s.<!INVISIBLE_MEMBER!>getName<!>()
s.name = ""
s.name = s.<!INVISIBLE_MEMBER!>name<!>
s.setName("")
}
}
}
abstract class NonSub {
fun test(s: Super) {
s.<!INVISIBLE_MEMBER!>name<!>
s.<!INVISIBLE_MEMBER!>getName<!>()
s.<!INVISIBLE_MEMBER!>name<!> = ""
s.<!INVISIBLE_MEMBER!>name<!> = s.<!INVISIBLE_MEMBER!>name<!>
s.setName("")
val anon1 = object : Super() {
fun testAnon() {
s.<!INVISIBLE_MEMBER!>name<!>
s.<!INVISIBLE_MEMBER!>getName<!>()
s.name = ""
s.name = s.<!INVISIBLE_MEMBER!>name<!>
s.setName("")
}
}
val anon2 = object {
fun testAnon() {
s.<!INVISIBLE_MEMBER!>name<!>
s.<!INVISIBLE_MEMBER!>getName<!>()
s.<!INVISIBLE_MEMBER!>name<!> = ""
s.<!INVISIBLE_MEMBER!>name<!> = s.<!INVISIBLE_MEMBER!>name<!>
s.setName("")
}
}
}
inner class Nested1 : Super() {
fun test(s: Super) {
s.<!INVISIBLE_MEMBER!>name<!>
s.<!INVISIBLE_MEMBER!>getName<!>()
s.name = ""
s.name = s.<!INVISIBLE_MEMBER!>name<!>
s.setName("")
}
}
class Nested2 {
fun test(s: Super) {
s.<!INVISIBLE_MEMBER!>name<!>
s.<!INVISIBLE_MEMBER!>getName<!>()
s.<!INVISIBLE_MEMBER!>name<!> = ""
s.<!INVISIBLE_MEMBER!>name<!> = s.<!INVISIBLE_MEMBER!>name<!>
s.setName("")
}
} }
} }
@@ -2,12 +2,12 @@ package
package j { package j {
public abstract class Super { public open class Super {
public constructor Super() public constructor Super()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
protected/*protected and package*/ abstract fun getName(): kotlin.String! protected/*protected and package*/ open fun getName(): kotlin.String!
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public abstract fun setName(/*0*/ s: kotlin.String!): kotlin.Unit public open fun setName(/*0*/ s: kotlin.String!): kotlin.Unit
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
} }
} }
@@ -15,13 +15,58 @@ package j {
package k { package k {
public fun test(/*0*/ s: j.Super): kotlin.Unit public fun test(/*0*/ s: j.Super): kotlin.Unit
public abstract class NonSub {
public constructor NonSub()
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 test(/*0*/ s: j.Super): kotlin.Unit
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
public final inner class Nested1 : j.Super {
public constructor Nested1()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
protected/*protected and package*/ open override /*1*/ /*fake_override*/ fun getName(): kotlin.String!
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun setName(/*0*/ s: kotlin.String!): kotlin.Unit
public final fun test(/*0*/ s: j.Super): kotlin.Unit
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
public final class Nested2 {
public constructor Nested2()
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 test(/*0*/ s: j.Super): kotlin.Unit
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
}
public abstract class Sub : j.Super { public abstract class Sub : j.Super {
public constructor Sub() public constructor Sub()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
protected/*protected and package*/ abstract override /*1*/ /*fake_override*/ fun getName(): kotlin.String! protected/*protected and package*/ open override /*1*/ /*fake_override*/ fun getName(): kotlin.String!
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public abstract override /*1*/ /*fake_override*/ fun setName(/*0*/ s: kotlin.String!): kotlin.Unit public open override /*1*/ /*fake_override*/ fun setName(/*0*/ s: kotlin.String!): kotlin.Unit
public final fun test(/*0*/ s: j.Super): kotlin.Unit public final fun test(/*0*/ s: j.Super): kotlin.Unit
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
public final inner class Nested1 : j.Super {
public constructor Nested1()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
protected/*protected and package*/ open override /*1*/ /*fake_override*/ fun getName(): kotlin.String!
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun setName(/*0*/ s: kotlin.String!): kotlin.Unit
public final fun test(/*0*/ s: j.Super): kotlin.Unit
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
public final class Nested2 {
public constructor Nested2()
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 test(/*0*/ s: j.Super): kotlin.Unit
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
} }
} }
@@ -5,8 +5,8 @@ import JavaClass
fun foo(javaClass: JavaClass) { fun foo(javaClass: JavaClass) {
val v = javaClass.<!INVISIBLE_REFERENCE!>something<!> val v = javaClass.<!INVISIBLE_REFERENCE!>something<!>
javaClass.something = 1 javaClass.<!INVISIBLE_REFERENCE!>something<!> = 1
javaClass.<!INVISIBLE_REFERENCE!>something<!>++ javaClass.<!INVISIBLE_REFERENCE, INVISIBLE_REFERENCE!>something<!>++
} }
// FILE: JavaClass.java // FILE: JavaClass.java