[FIR] Implement INVISIBLE_SETTER

This commit is contained in:
Ivan Kochurkin
2021-07-27 22:40:00 +03:00
committed by teamcityserver
parent ca4410aa53
commit b3d7ed569d
39 changed files with 288 additions and 180 deletions
@@ -23,6 +23,7 @@ import org.jetbrains.kotlin.fir.symbols.impl.*
import org.jetbrains.kotlin.fir.types.ConeKotlinType
import org.jetbrains.kotlin.lexer.KtKeywordToken
import org.jetbrains.kotlin.lexer.KtModifierKeywordToken
import org.jetbrains.kotlin.name.CallableId
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.*
@@ -86,6 +87,11 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") {
val VAL_OR_VAR_ON_SECONDARY_CONSTRUCTOR_PARAMETER by warning<KtParameter>(PositioningStrategy.VAL_OR_VAR_NODE) {
parameter<KtKeywordToken>("valOrVar")
}
val INVISIBLE_SETTER by error<PsiElement>(PositioningStrategy.ASSIGNMENT_LHS) {
parameter<FirPropertySymbol>("property")
parameter<Visibility>("visibility")
parameter<CallableId>("callableId")
}
}
val UNRESOLVED by object : DiagnosticGroup("Unresolved") {
@@ -32,6 +32,7 @@ import org.jetbrains.kotlin.fir.symbols.impl.FirVariableSymbol
import org.jetbrains.kotlin.fir.types.ConeKotlinType
import org.jetbrains.kotlin.lexer.KtKeywordToken
import org.jetbrains.kotlin.lexer.KtModifierKeywordToken
import org.jetbrains.kotlin.name.CallableId
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.KtAnnotationEntry
@@ -116,6 +117,7 @@ object FirErrors {
val VAL_OR_VAR_ON_FUN_PARAMETER by warning1<KtParameter, KtKeywordToken>(SourceElementPositioningStrategies.VAL_OR_VAR_NODE)
val VAL_OR_VAR_ON_CATCH_PARAMETER by warning1<KtParameter, KtKeywordToken>(SourceElementPositioningStrategies.VAL_OR_VAR_NODE)
val VAL_OR_VAR_ON_SECONDARY_CONSTRUCTOR_PARAMETER by warning1<KtParameter, KtKeywordToken>(SourceElementPositioningStrategies.VAL_OR_VAR_NODE)
val INVISIBLE_SETTER by error3<PsiElement, FirPropertySymbol, Visibility, CallableId>(SourceElementPositioningStrategies.ASSIGNMENT_LHS)
// Unresolved
val INVISIBLE_REFERENCE by error1<PsiElement, FirBasedSymbol<*>>(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED)
@@ -59,7 +59,7 @@ object CommonExpressionCheckers : ExpressionCheckers() {
override val variableAssignmentCheckers: Set<FirVariableAssignmentChecker>
get() = setOf(
FirValReassignmentChecker,
FirReassignmentAndInvisibleSetterChecker,
FirAssignmentTypeMismatchChecker
)
@@ -0,0 +1,125 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.fir.analysis.checkers.expression
import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.checkers.context.findClosest
import org.jetbrains.kotlin.fir.analysis.checkers.toRegularClassSymbol
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
import org.jetbrains.kotlin.fir.declarations.FirPropertyAccessor
import org.jetbrains.kotlin.fir.declarations.utils.isCompanion
import org.jetbrains.kotlin.fir.declarations.utils.visibility
import org.jetbrains.kotlin.fir.expressions.FirExpressionWithSmartcast
import org.jetbrains.kotlin.fir.expressions.FirVariableAssignment
import org.jetbrains.kotlin.fir.expressions.toResolvedCallableSymbol
import org.jetbrains.kotlin.fir.languageVersionSettings
import org.jetbrains.kotlin.fir.references.FirBackingFieldReference
import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference
import org.jetbrains.kotlin.fir.resolve.calls.ExpressionReceiverValue
import org.jetbrains.kotlin.fir.symbols.SymbolInternals
import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirValueParameterSymbol
import org.jetbrains.kotlin.fir.types.toSymbol
import org.jetbrains.kotlin.fir.visibilityChecker
object FirReassignmentAndInvisibleSetterChecker : FirVariableAssignmentChecker() {
override fun check(expression: FirVariableAssignment, context: CheckerContext, reporter: DiagnosticReporter) {
checkInvisibleSetter(expression, context, reporter)
checkValReassignmentViaBackingField(expression, context, reporter)
checkValReassignmentOnValueParameter(expression, context, reporter)
}
private fun checkInvisibleSetter(
expression: FirVariableAssignment,
context: CheckerContext,
reporter: DiagnosticReporter
) {
fun shouldInvisibleSetterBeReported(symbol: FirPropertySymbol): Boolean {
val setterSymbol = symbol.setterSymbol
@OptIn(SymbolInternals::class)
val setterFir = setterSymbol?.fir
if (setterFir != null) {
val isVisible = context.session.visibilityChecker.isVisible(
setterFir,
context.session,
context.findClosest()!!,
context.containingDeclarations,
ExpressionReceiverValue(expression.dispatchReceiver),
)
if (!isVisible) {
// Report SUBCLASS_CANT_CALL_COMPANION_PROTECTED_NON_STATIC in another checker
val dispatchReceiverTypeSymbol = symbol.dispatchReceiverType?.toSymbol(context.session)
return setterFir.visibility != Visibilities.Protected ||
dispatchReceiverTypeSymbol !is FirRegularClassSymbol ||
!dispatchReceiverTypeSymbol.isCompanion
}
}
return false
}
val callableSymbol = expression.calleeReference.toResolvedCallableSymbol()
if (callableSymbol is FirPropertySymbol && shouldInvisibleSetterBeReported(callableSymbol)) {
val explicitReceiver = expression.explicitReceiver
// Try to get type from smartcast
if (explicitReceiver is FirExpressionWithSmartcast) {
val symbol = explicitReceiver.originalType.toRegularClassSymbol(context.session)
if (symbol != null) {
for (declarationSymbol in symbol.declarationSymbols) {
if (declarationSymbol is FirPropertySymbol && declarationSymbol.name == callableSymbol.name) {
if (!shouldInvisibleSetterBeReported(declarationSymbol)) {
return
}
}
}
}
}
reporter.reportOn(
expression.source,
FirErrors.INVISIBLE_SETTER,
callableSymbol,
callableSymbol.setterSymbol!!.visibility,
callableSymbol.callableId,
context
)
}
}
private fun checkValReassignmentViaBackingField(
expression: FirVariableAssignment,
context: CheckerContext,
reporter: DiagnosticReporter
) {
val backingFieldReference = expression.lValue as? FirBackingFieldReference ?: return
val propertySymbol = backingFieldReference.resolvedSymbol
if (propertySymbol.isVar) return
val closestGetter = context.findClosest<FirPropertyAccessor> { it.isGetter }?.symbol ?: return
if (propertySymbol.getterSymbol != closestGetter) return
backingFieldReference.source?.let {
if (context.session.languageVersionSettings.supportsFeature(LanguageFeature.RestrictionOfValReassignmentViaBackingField)) {
reporter.reportOn(it, FirErrors.VAL_REASSIGNMENT_VIA_BACKING_FIELD_ERROR, propertySymbol, context)
} else {
reporter.reportOn(it, FirErrors.VAL_REASSIGNMENT_VIA_BACKING_FIELD, propertySymbol, context)
}
}
}
private fun checkValReassignmentOnValueParameter(
expression: FirVariableAssignment,
context: CheckerContext,
reporter: DiagnosticReporter
) {
val valueParameter = (expression.lValue as? FirResolvedNamedReference)?.resolvedSymbol as? FirValueParameterSymbol ?: return
reporter.reportOn(expression.lValue.source, FirErrors.VAL_REASSIGNMENT, valueParameter, context)
}
}
@@ -1,55 +0,0 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.fir.analysis.checkers.expression
import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.checkers.context.findClosest
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
import org.jetbrains.kotlin.fir.declarations.FirPropertyAccessor
import org.jetbrains.kotlin.fir.expressions.FirVariableAssignment
import org.jetbrains.kotlin.fir.languageVersionSettings
import org.jetbrains.kotlin.fir.references.FirBackingFieldReference
import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference
import org.jetbrains.kotlin.fir.symbols.impl.FirValueParameterSymbol
object FirValReassignmentChecker : FirVariableAssignmentChecker() {
override fun check(expression: FirVariableAssignment, context: CheckerContext, reporter: DiagnosticReporter) {
checkValReassignmentViaBackingField(expression, context, reporter)
checkValReassignmentOnValueParameter(expression, context, reporter)
}
private fun checkValReassignmentViaBackingField(
expression: FirVariableAssignment,
context: CheckerContext,
reporter: DiagnosticReporter
) {
val backingFieldReference = expression.lValue as? FirBackingFieldReference ?: return
val propertySymbol = backingFieldReference.resolvedSymbol
if (propertySymbol.isVar) return
val closestGetter = context.findClosest<FirPropertyAccessor> { it.isGetter }?.symbol ?: return
if (propertySymbol.getterSymbol != closestGetter) return
backingFieldReference.source?.let {
if (context.session.languageVersionSettings.supportsFeature(LanguageFeature.RestrictionOfValReassignmentViaBackingField)) {
reporter.reportOn(it, FirErrors.VAL_REASSIGNMENT_VIA_BACKING_FIELD_ERROR, propertySymbol, context)
} else {
reporter.reportOn(it, FirErrors.VAL_REASSIGNMENT_VIA_BACKING_FIELD, propertySymbol, context)
}
}
}
private fun checkValReassignmentOnValueParameter(
expression: FirVariableAssignment,
context: CheckerContext,
reporter: DiagnosticReporter
) {
val valueParameter = (expression.lValue as? FirResolvedNamedReference)?.resolvedSymbol as? FirValueParameterSymbol ?: return
reporter.reportOn(expression.lValue.source, FirErrors.VAL_REASSIGNMENT, valueParameter, context)
}
}
@@ -16,6 +16,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnosticRenderers.FQ_N
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnosticRenderers.COLLECTION
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnosticRenderers.MODULE_DATA
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnosticRenderers.FUNCTION_PARAMETERS
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnosticRenderers.NAME_OF_CONTAINING_DECLARATION_OR_FILE
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnosticRenderers.NOT_RENDERED
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnosticRenderers.NULLABLE_STRING
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnosticRenderers.RENDER_CLASS_OR_OBJECT
@@ -227,6 +228,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.INTERFACE_WITH_SU
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.INVALID_IF_AS_EXPRESSION
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.INVALID_TYPE_OF_ANNOTATION_MEMBER
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.INVISIBLE_REFERENCE
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.INVISIBLE_SETTER
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.IS_ENUM_ENTRY
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ITERATOR_AMBIGUITY
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.KCLASS_WITH_NULLABLE_TYPE_PARAMETER_IN_SIGNATURE
@@ -480,6 +482,7 @@ class FirDefaultErrorMessages {
// Unresolved
map.put(INVISIBLE_REFERENCE, "Symbol {0} is invisible", SYMBOL)
map.put(INVISIBLE_SETTER, "Cannot access ''{0}'': it is {1} in {2}", VARIABLE_NAME, VISIBILITY, NAME_OF_CONTAINING_DECLARATION_OR_FILE)
map.put(UNRESOLVED_REFERENCE, "Unresolved reference: {0}", NULLABLE_STRING)
map.put(UNRESOLVED_LABEL, "Unresolved label")
map.put(DESERIALIZATION_ERROR, "Deserialization error")
@@ -13,16 +13,14 @@ import org.jetbrains.kotlin.diagnostics.rendering.Renderer
import org.jetbrains.kotlin.fir.FirElement
import org.jetbrains.kotlin.fir.FirModuleData
import org.jetbrains.kotlin.fir.FirRenderer
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.declarations.utils.*
import org.jetbrains.kotlin.fir.render
import org.jetbrains.kotlin.fir.resolve.dfa.cfg.isLocalClassOrAnonymousObject
import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.firUnsafe
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
import org.jetbrains.kotlin.fir.symbols.SymbolInternals
import org.jetbrains.kotlin.fir.symbols.impl.*
import org.jetbrains.kotlin.fir.types.ConeKotlinType
import org.jetbrains.kotlin.fir.types.render
import org.jetbrains.kotlin.name.CallableId
object FirDiagnosticRenderers {
val NULLABLE_STRING = Renderer<String?> { it ?: "null" }
@@ -136,6 +134,15 @@ object FirDiagnosticRenderers {
"Module ${it.name}"
}
val NAME_OF_CONTAINING_DECLARATION_OR_FILE = Renderer { symbol: CallableId ->
val classId = symbol.classId
if (classId == null) {
"file"
} else {
"'${classId}'"
}
}
@Suppress("FunctionName")
fun <T> COLLECTION(renderer: ContextIndependentParameterRenderer<T>): ContextIndependentParameterRenderer<Collection<T>> {
return Renderer { list ->
@@ -10,6 +10,7 @@ import org.jetbrains.kotlin.descriptors.java.JavaVisibilities
import org.jetbrains.kotlin.fir.*
import org.jetbrains.kotlin.fir.declarations.FirDeclaration
import org.jetbrains.kotlin.fir.declarations.FirFile
import org.jetbrains.kotlin.fir.declarations.synthetic.FirSyntheticPropertyAccessor
import org.jetbrains.kotlin.fir.resolve.calls.ReceiverValue
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
@@ -29,7 +30,13 @@ object FirJavaVisibilityChecker : FirVisibilityChecker() {
true
} else {
val ownerId = symbol.getOwnerId()
ownerId != null && canSeeProtectedMemberOf(containingDeclarations, dispatchReceiver, ownerId, session)
ownerId != null && canSeeProtectedMemberOf(
containingDeclarations,
dispatchReceiver,
ownerId,
symbol.fir is FirSyntheticPropertyAccessor,
session
)
}
}
@@ -5,22 +5,23 @@
package org.jetbrains.kotlin.fir
import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.descriptors.Visibility
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.declarations.synthetic.FirSyntheticPropertyAccessor
import org.jetbrains.kotlin.fir.declarations.utils.*
import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccessExpression
import org.jetbrains.kotlin.fir.expressions.FirThisReceiverExpression
import org.jetbrains.kotlin.fir.references.impl.FirExplicitSuperReference
import org.jetbrains.kotlin.fir.resolve.*
import org.jetbrains.kotlin.fir.resolve.calls.Candidate
import org.jetbrains.kotlin.fir.resolve.calls.FirSyntheticFunctionSymbol
import org.jetbrains.kotlin.fir.resolve.calls.ReceiverValue
import org.jetbrains.kotlin.fir.resolve.firProvider
import org.jetbrains.kotlin.fir.resolve.fullyExpandedType
import org.jetbrains.kotlin.fir.resolve.lookupSuperTypes
import org.jetbrains.kotlin.fir.resolve.symbolProvider
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirClassLikeSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol
import org.jetbrains.kotlin.fir.symbols.impl.*
import org.jetbrains.kotlin.fir.types.ConeClassLikeType
import org.jetbrains.kotlin.fir.types.toSymbol
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
@@ -116,7 +117,13 @@ abstract class FirVisibilityChecker : FirSessionComponent {
Visibilities.Protected -> {
val ownerId = symbol.getOwnerId()
ownerId != null && canSeeProtectedMemberOf(containingDeclarations, dispatchReceiver, ownerId, session)
ownerId != null && canSeeProtectedMemberOf(
containingDeclarations,
dispatchReceiver,
ownerId,
symbol.fir is FirSyntheticPropertyAccessor,
session
)
}
else -> platformVisibilityCheck(
@@ -171,22 +178,43 @@ abstract class FirVisibilityChecker : FirSessionComponent {
}
private fun canSeeProtectedMemberOf(
containingUseSiteClass: FirClass,
containingUseSiteClassSymbol: FirClassSymbol<*>,
dispatchReceiver: ReceiverValue?,
ownerId: ClassId, session: FirSession
ownerId: ClassId,
isSyntheticProperty: Boolean,
session: FirSession
): Boolean {
dispatchReceiver?.ownerIfCompanion(session)?.let { companionOwnerClassId ->
if (containingUseSiteClass.isSubClass(companionOwnerClassId, session)) return true
if (containingUseSiteClassSymbol.isSubClass(companionOwnerClassId, session)) return true
}
// TODO: Add check for receiver, see org.jetbrains.kotlin.descriptors.Visibility#doesReceiverFitForProtectedVisibility
return containingUseSiteClass.isSubClass(ownerId, session)
if (containingUseSiteClassSymbol.isSubClass(ownerId, session)) {
val receiverExpression = dispatchReceiver?.receiverExpression
if (receiverExpression == null ||
receiverExpression is FirThisReceiverExpression ||
(receiverExpression is FirQualifiedAccessExpression && receiverExpression.calleeReference is FirExplicitSuperReference) ||
dispatchReceiver.type.toSymbol(session).isSubClass(containingUseSiteClassSymbol.classId, session)
) {
return true
}
if (isSyntheticProperty) {
return if (session.languageVersionSettings.supportsFeature(LanguageFeature.ImproveReportingDiagnosticsOnProtectedMembersOfBaseClass))
containingUseSiteClassSymbol.classId.packageFqName == ownerId.packageFqName
else
true
}
}
return false
}
private fun FirClass.isSubClass(ownerId: ClassId, session: FirSession): Boolean {
private fun FirBasedSymbol<*>?.isSubClass(ownerId: ClassId, session: FirSession): Boolean {
val classSymbol = this as? FirClassSymbol<*> ?: return false
val classId = classSymbol.classId
if (classId.isSame(ownerId)) return true
return lookupSuperTypes(this, lookupInterfaces = true, deep = true, session).any { superType ->
return lookupSuperTypes(classSymbol, lookupInterfaces = true, deep = true, session).any { superType ->
(superType as? ConeClassLikeType)?.fullyExpandedType(session)?.lookupTag?.classId?.isSame(ownerId) == true
}
}
@@ -207,14 +235,16 @@ abstract class FirVisibilityChecker : FirSessionComponent {
protected fun canSeeProtectedMemberOf(
containingDeclarationOfUseSite: List<FirDeclaration>,
dispatchReceiver: ReceiverValue?,
ownerId: ClassId, session: FirSession
ownerId: ClassId,
isSyntheticProperty: Boolean,
session: FirSession
): Boolean {
if (canSeePrivateMemberOf(containingDeclarationOfUseSite, ownerId, session)) return true
for (containingDeclaration in containingDeclarationOfUseSite) {
if (containingDeclaration !is FirClass) continue
val boundSymbol = containingDeclaration.symbol
if (canSeeProtectedMemberOf(boundSymbol.fir, dispatchReceiver, ownerId, session)) return true
if (canSeeProtectedMemberOf(boundSymbol.fir.symbol, dispatchReceiver, ownerId, isSyntheticProperty, session)) return true
}
return false
@@ -49,9 +49,20 @@ fun lookupSuperTypes(
useSiteSession: FirSession,
supertypeSupplier: SupertypeSupplier = SupertypeSupplier.Default,
substituteTypes: Boolean = false
): List<ConeClassLikeType> {
return lookupSuperTypes(klass.symbol, lookupInterfaces, deep, useSiteSession, supertypeSupplier, substituteTypes)
}
fun lookupSuperTypes(
classSymbol: FirClassSymbol<*>,
lookupInterfaces: Boolean,
deep: Boolean,
useSiteSession: FirSession,
supertypeSupplier: SupertypeSupplier = SupertypeSupplier.Default,
substituteTypes: Boolean = false
): List<ConeClassLikeType> {
return SmartList<ConeClassLikeType>().also {
klass.symbol.collectSuperTypes(it, SmartSet.create(), deep, lookupInterfaces, substituteTypes, useSiteSession, supertypeSupplier)
classSymbol.collectSuperTypes(it, SmartSet.create(), deep, lookupInterfaces, substituteTypes, useSiteSession, supertypeSupplier)
}
}
@@ -6,6 +6,7 @@
package org.jetbrains.kotlin.fir.references.builder
import kotlin.contracts.*
import org.jetbrains.kotlin.fir.FirImplementationDetail
import org.jetbrains.kotlin.fir.FirSourceElement
import org.jetbrains.kotlin.fir.builder.FirBuilderDsl
import org.jetbrains.kotlin.fir.references.FirSuperReference
@@ -24,6 +25,7 @@ class FirExplicitSuperReferenceBuilder {
var labelName: String? = null
lateinit var superTypeRef: FirTypeRef
@OptIn(FirImplementationDetail::class)
fun build(): FirSuperReference {
return FirExplicitSuperReference(
source,
@@ -5,6 +5,7 @@
package org.jetbrains.kotlin.fir.references.impl
import org.jetbrains.kotlin.fir.FirImplementationDetail
import org.jetbrains.kotlin.fir.FirSourceElement
import org.jetbrains.kotlin.fir.references.FirSuperReference
import org.jetbrains.kotlin.fir.types.FirTypeRef
@@ -15,7 +16,7 @@ import org.jetbrains.kotlin.fir.visitors.*
* DO NOT MODIFY IT MANUALLY
*/
internal class FirExplicitSuperReference(
class FirExplicitSuperReference @FirImplementationDetail constructor(
override val source: FirSourceElement?,
override val labelName: String?,
override var superTypeRef: FirTypeRef,
@@ -399,7 +399,9 @@ object ImplementationConfigurator : AbstractFirTreeImplementationConfigurator()
}
}
impl(superReference, "FirExplicitSuperReference")
impl(superReference, "FirExplicitSuperReference") {
publicImplementation()
}
noImpl(controlFlowGraphReference)
@@ -22,7 +22,7 @@ class Test: ATest(), ITest {
fun main() {
val test = Test()
test.prop = 12
<!INVISIBLE_SETTER!>test.prop<!> = 12
val itest: ITest = test
itest.prop = 12 // No error here
@@ -23,23 +23,23 @@ class P {
fun foo() {
val p = P()
p.x = 34 //should be an error here
<!INVISIBLE_SETTER!>p.x<!> = 34 //should be an error here
p.y = 23
fun inner() {
p.x = 44
<!INVISIBLE_SETTER!>p.x<!> = 44
}
}
class R {
val p = P();
init {
p.x = 42
<!INVISIBLE_SETTER!>p.x<!> = 42
}
val testInGetterInOtherClass : Int
get() {
p.x = 33
<!INVISIBLE_SETTER!>p.x<!> = 33
return 3
}
}
@@ -50,4 +50,4 @@ fun test() {
<!UNRESOLVED_REFERENCE!>p<!>.x = 43
}
}
}
}
@@ -1,36 +0,0 @@
//KT-2960 Perform control flow checks for package property initializers
package b
class P {
var x : Int = 0
private set
}
val p = P()
var f = { -> p.x = 32 }
val o = object {
fun run() {
p.x = 4
val z : Int
doSmth(<!UNINITIALIZED_VARIABLE!>z<!>)
}
}
val g = { ->
val x: Int
doSmth(<!UNINITIALIZED_VARIABLE!>x<!>)
}
class A {
val a : Int = 1
get() {
val x : Int
doSmth(<!UNINITIALIZED_VARIABLE!>x<!>)
return field
}
}
fun doSmth(i: Int) = i
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
//KT-2960 Perform control flow checks for package property initializers
package b
@@ -1,17 +0,0 @@
open class X(s : String) {
public var n: String = s
private set
}
class Z : X("subclass") {
fun print(): String {
n = n
return n;
}
}
fun box() : String {
return Z().print() //error
}
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
open class X(s : String) {
public var n: String = s
private set
@@ -40,7 +40,7 @@ fun test() {
val po = <!INVISIBLE_REFERENCE!>PO<!>
val v = xx
xx = 40
<!INVISIBLE_SETTER("xx; private; file")!>xx<!> = 40
}
class B : <!EXPOSED_SUPER_CLASS, INVISIBLE_REFERENCE!>A<!>() {}
@@ -1,9 +0,0 @@
class A<T> {
public var x: Int = 0
private set
}
fun main() {
val a = A<Any>()
a.x = 1
}
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
class A<T> {
public var x: Int = 0
private set
+2 -2
View File
@@ -6,8 +6,8 @@ class B: A()
class C: A() {
fun bar() {
A().foo()
B().foo()
A().<!INVISIBLE_REFERENCE!>foo<!>()
B().<!INVISIBLE_REFERENCE!>foo<!>()
}
}
@@ -13,6 +13,6 @@ class B {
class C: A() {
init {
B.foo() // Error: receiver is not suitable
B.<!INVISIBLE_REFERENCE!>foo<!>() // Error: receiver is not suitable
}
}
@@ -21,9 +21,8 @@ class B : A() {
b.foo
b.bar = b.bar + ""
a.foo
// TODO: should be INVISIBLE_SETTER
a.bar = a.bar + ""
a.<!INVISIBLE_REFERENCE!>foo<!>
<!INVISIBLE_SETTER!>a.bar<!> = a.bar + ""
if (a is B) {
a.foo
@@ -32,14 +31,13 @@ class B : A() {
if (d.x is B) {
d.x.abc // Ok
d.x.foo
// TODO: should be INVISIBLE_SETTER
d.x.bar = d.x.bar + ""
d.x.<!INVISIBLE_REFERENCE!>foo<!>
<!INVISIBLE_SETTER!>d.x.bar<!> = d.x.bar + ""
}
}
}
fun baz(a: A) {
a.<!INVISIBLE_REFERENCE!>foo<!>
a.bar = a.bar + ""
<!INVISIBLE_SETTER!>a.bar<!> = a.bar + ""
}
@@ -22,7 +22,6 @@ class B : A() {
b.bar = b.bar + ""
a.<!INVISIBLE_MEMBER!>foo<!>
// TODO: should be INVISIBLE_SETTER
a.<!INVISIBLE_SETTER!>bar<!> = a.bar + ""
if (a is B) {
@@ -33,7 +32,6 @@ class B : A() {
if (d.x is B) {
d.x.abc // Ok
d.x.<!INVISIBLE_MEMBER!>foo<!>
// TODO: should be INVISIBLE_SETTER
d.x.<!INVISIBLE_SETTER!>bar<!> = d.x.bar + ""
}
}
@@ -11,7 +11,7 @@ class Data(var x: A)
class B : A() {
fun baz(a: A, b: B, d: Data) {
a.foo { }
a.<!INVISIBLE_REFERENCE!>foo<!> { }
b.foo { }
@@ -20,7 +20,7 @@ class B : A() {
}
if (d.x is B) {
d.x.foo {}
d.x.<!INVISIBLE_REFERENCE!>foo<!> {}
}
}
}
@@ -11,8 +11,8 @@ fun BaseOuter.foo(): String = ""
class Derived : BaseOuter() {
fun test(foo: Foo) {
if (foo.base is Derived) {
foo.base.foo() checkType { <!INAPPLICABLE_CANDIDATE!>_<!><String>() } // Resolved to extension
foo.base.bar()
foo.base.foo() checkType { _<String>() } // Resolved to extension
foo.base.<!INVISIBLE_REFERENCE!>bar<!>()
}
}
}
@@ -11,11 +11,11 @@ class Derived : Base() {
override fun bar() { }
protected fun baz(x: Base) {
x.foo()
x.bar()
x.<!INVISIBLE_REFERENCE!>foo<!>()
x.<!INVISIBLE_REFERENCE!>bar<!>()
x.x = x.x + 1
x.y = x.y + 1
x.<!INVISIBLE_REFERENCE!>x<!> = x.<!INVISIBLE_REFERENCE!>x<!> + 1
<!INVISIBLE_SETTER!>x.y<!> = x.y + 1
if (x is Derived) {
x.foo()
@@ -72,7 +72,7 @@ class E : C() {
class F : C() {
fun test8(c: C) {
doSmth(c.i)
doSmth(c.<!INVISIBLE_REFERENCE!>i<!>)
}
}
@@ -8,7 +8,7 @@ fun foo(javaClass: JavaClass) {
javaClass.<!INVISIBLE_REFERENCE!>somethingProtected<!>
javaClass.<!INVISIBLE_REFERENCE!>somethingPrivate<!>
javaClass.<!INVISIBLE_REFERENCE!>somethingPackage<!>
javaClass.somethingPublic = 1
<!INVISIBLE_SETTER!>javaClass.somethingPublic<!> = 1
}
// FILE: JavaClass.java
@@ -12,7 +12,7 @@ fun foo(javaClass: JavaClass) {
class X : JavaClass() {
fun foo(other: JavaClass) {
doSomething { bar() }
other.doSomething { bar() }
other.<!INVISIBLE_REFERENCE!>doSomething<!> { bar() }
}
}
@@ -18,12 +18,12 @@ class Data(var x: Foo)
class B : Foo() {
fun baz(a: Foo, t: Foo, d: Data) {
a.bar = t.bar
a.foo = t.foo
<!INVISIBLE_SETTER!>a.bar<!> = t.bar
<!INVISIBLE_SETTER!>a.foo<!> = t.foo
if (d.x is B) {
d.x.bar = d.x.bar + ""
d.x.foo = d.x.foo + ""
<!INVISIBLE_SETTER!>d.x.bar<!> = d.x.bar + ""
<!INVISIBLE_SETTER!>d.x.foo<!> = d.x.foo + ""
}
}
}
@@ -19,11 +19,11 @@ class Data(var x: Foo)
class B : Foo() {
fun baz(a: Foo, t: Foo, d: Data) {
a.bar = t.bar
a.foo = t.foo
<!INVISIBLE_SETTER!>a.foo<!> = t.foo
if (d.x is B) {
d.x.bar = d.x.bar + ""
d.x.foo = d.x.foo + ""
<!INVISIBLE_SETTER!>d.x.foo<!> = d.x.foo + ""
}
}
}
@@ -13,11 +13,11 @@ class Data(var x: Foo)
class B : Foo() {
fun baz(a: Foo, t: Foo, d: Data) {
a.bar = t.bar
a.foo = t.foo
<!INVISIBLE_SETTER!>a.foo<!> = t.foo
if (d.x is B) {
d.x.bar = d.x.bar + ""
d.x.foo = d.x.foo + ""
<!INVISIBLE_SETTER!>d.x.foo<!> = d.x.foo + ""
}
}
}
@@ -27,6 +27,7 @@ import org.jetbrains.kotlin.idea.frontend.api.symbols.*
import org.jetbrains.kotlin.idea.frontend.api.types.KtType
import org.jetbrains.kotlin.lexer.KtKeywordToken
import org.jetbrains.kotlin.lexer.KtModifierKeywordToken
import org.jetbrains.kotlin.name.CallableId
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.KtExpression
@@ -300,6 +301,7 @@ private object FirToKtConversionCreator {
FqName::class,
FirModuleData::class,
ExpectActualCompatibility.Incompatible::class,
CallableId::class
)
private val KType.kClass: KClass<*>
@@ -241,6 +241,15 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert
token,
)
}
add(FirErrors.INVISIBLE_SETTER) { firDiagnostic ->
InvisibleSetterImpl(
firSymbolBuilder.variableLikeBuilder.buildVariableSymbol(firDiagnostic.a.fir),
firDiagnostic.b,
firDiagnostic.c,
firDiagnostic as FirPsiDiagnostic,
token,
)
}
add(FirErrors.INVISIBLE_REFERENCE) { firDiagnostic ->
InvisibleReferenceImpl(
firSymbolBuilder.buildSymbol(firDiagnostic.a.fir),
@@ -26,6 +26,7 @@ import org.jetbrains.kotlin.idea.frontend.api.symbols.KtVariableSymbol
import org.jetbrains.kotlin.idea.frontend.api.types.KtType
import org.jetbrains.kotlin.lexer.KtKeywordToken
import org.jetbrains.kotlin.lexer.KtModifierKeywordToken
import org.jetbrains.kotlin.name.CallableId
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.KtAnnotationEntry
@@ -197,6 +198,13 @@ sealed class KtFirDiagnostic<PSI : PsiElement> : KtDiagnosticWithPsi<PSI> {
abstract val valOrVar: KtKeywordToken
}
abstract class InvisibleSetter : KtFirDiagnostic<PsiElement>() {
override val diagnosticClass get() = InvisibleSetter::class
abstract val property: KtVariableSymbol
abstract val visibility: Visibility
abstract val callableId: CallableId
}
abstract class InvisibleReference : KtFirDiagnostic<PsiElement>() {
override val diagnosticClass get() = InvisibleReference::class
abstract val reference: KtSymbol
@@ -28,6 +28,7 @@ import org.jetbrains.kotlin.idea.frontend.api.tokens.ValidityToken
import org.jetbrains.kotlin.idea.frontend.api.types.KtType
import org.jetbrains.kotlin.lexer.KtKeywordToken
import org.jetbrains.kotlin.lexer.KtModifierKeywordToken
import org.jetbrains.kotlin.name.CallableId
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.KtAnnotationEntry
@@ -282,6 +283,16 @@ internal class ValOrVarOnSecondaryConstructorParameterImpl(
override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic)
}
internal class InvisibleSetterImpl(
override val property: KtVariableSymbol,
override val visibility: Visibility,
override val callableId: CallableId,
firDiagnostic: FirPsiDiagnostic,
override val token: ValidityToken,
) : KtFirDiagnostic.InvisibleSetter(), KtAbstractFirDiagnostic<PsiElement> {
override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic)
}
internal class InvisibleReferenceImpl(
override val reference: KtSymbol,
firDiagnostic: FirPsiDiagnostic,