K2: fix visibility checks for static overrides via imported from static

#KT-53441 In Progress
This commit is contained in:
Mikhail Glukhikh
2022-10-27 12:11:21 +02:00
committed by Space Team
parent cc1a094b6c
commit f070401bb5
13 changed files with 107 additions and 43 deletions
@@ -1,4 +1,4 @@
FILE: main.kt
public final fun test(list: R|kotlin/collections/List<kotlin/String>|, string: R|kotlin/String|): R|kotlin/Unit| {
R|/Matchers.assertThat|<R|ft<kotlin/collections/List<kotlin/String>, kotlin/collections/List<kotlin/String>?>|>(R|<local>/list|, R|/Matchers.hasItem|<R|kotlin/String!|>(R|<local>/string|))
Q|Matchers|.R|/Matchers.assertThat|<R|ft<kotlin/collections/List<kotlin/String>, kotlin/collections/List<kotlin/String>?>|>(R|<local>/list|, Q|Matchers|.R|/Matchers.hasItem|<R|kotlin/String!|>(R|<local>/string|))
}
@@ -1,4 +1,4 @@
FILE: FlexiblePrimitiveOverloading.kt
public final fun foo(): R|kotlin/Unit| {
R|java/lang/Integer.getInteger|(String(text), Int(239))
Q|java/lang/Integer|.R|java/lang/Integer.getInteger|(String(text), Int(239))
}
@@ -102,7 +102,7 @@ object FirConflictsChecker : FirBasicDeclarationChecker() {
if (isExpectAndActual(declaration, conflicting)) return
if (
conflicting is FirMemberDeclaration &&
!session.visibilityChecker.isVisible(conflicting, session, containingFile, emptyList(), null)
!session.visibilityChecker.isVisible(conflicting, session, containingFile, emptyList(), dispatchReceiver = null)
) return
val declarationIsLowPriority = hasLowPriorityAnnotation(declaration.annotations)
val conflictingIsLowPriority = hasLowPriorityAnnotation(conflicting.annotations)
@@ -171,7 +171,7 @@ object FirOverrideChecker : FirClassChecker() {
context.session,
file,
containingDeclarations,
null,
dispatchReceiver = null,
skipCheckForContainingClassVisibility = true
)
}
@@ -281,7 +281,7 @@ object FirOverrideChecker : FirClassChecker() {
context.session,
file,
containingDeclarations,
null,
dispatchReceiver = null,
skipCheckForContainingClassVisibility = true
)
}?.originalOrSelf() ?: return
@@ -35,9 +35,8 @@ object FirVisibilityQualifierChecker : FirResolvedQualifierChecker() {
val firFile = context.containingDeclarations.firstOrNull() as? FirFile ?: return
val firClassLikeDeclaration = symbol.fir
if (!context.session.visibilityChecker.isVisible(
if (!context.session.visibilityChecker.isClassLikeVisible(
firClassLikeDeclaration, context.session, firFile, context.containingDeclarations,
dispatchReceiver = null,
)
) {
reporter.reportOn(expression.source, FirErrors.INVISIBLE_REFERENCE, symbol, context)
@@ -72,6 +72,25 @@ abstract class FirVisibilityChecker : FirSessionComponent {
}
}
fun isClassLikeVisible(
declaration: FirClassLikeDeclaration,
session: FirSession,
useSiteFile: FirFile,
containingDeclarations: List<FirDeclaration>,
): Boolean {
return isVisible(
declaration,
session,
useSiteFile,
containingDeclarations,
dispatchReceiver = null,
isCallToPropertySetter = false,
staticQualifierClassForCallable = null,
skipCheckForContainingClassVisibility = false,
supertypeSupplier = SupertypeSupplier.Default
)
}
fun isVisible(
declaration: FirMemberDeclaration,
session: FirSession,
@@ -79,6 +98,7 @@ abstract class FirVisibilityChecker : FirSessionComponent {
containingDeclarations: List<FirDeclaration>,
dispatchReceiver: ReceiverValue?,
isCallToPropertySetter: Boolean = false,
staticQualifierClassForCallable: FirRegularClass? = null,
// There's no need to check if containing class is visible in case we check if a member might be overridden in a subclass
// because visibility for its supertype that contain overridden member is being checked when resolving the type reference.
// Such flag is not necessary in FE1.0, since there are full structure of fake overrides and containing declaration for overridden
@@ -108,8 +128,14 @@ abstract class FirVisibilityChecker : FirSessionComponent {
supertypeSupplier
) ?: return true
return generateSequence(parentClass) { it.containingNonLocalClass(session) }.all { parent ->
val classLikeToCheck =
if (staticQualifierClassForCallable?.isSubClass(parent.symbol.toLookupTag(), session, supertypeSupplier) == true) {
staticQualifierClassForCallable
} else {
parent
}
isSpecificDeclarationVisible(
parent,
classLikeToCheck,
session,
useSiteFile,
containingDeclarations,
@@ -61,9 +61,14 @@ abstract class FirAbstractImportingScope(
for (import in imports) {
val importedName = name ?: import.importedName ?: continue
if (isExcluded(import, importedName)) continue
val staticsScope = import.resolvedParentClassId?.let(::getStaticsScope)
val parentClassId = import.resolvedParentClassId
val staticsScope = parentClassId?.let { getStaticsScope(it) }
if (staticsScope != null) {
staticsScope.processFunctionsByName(importedName, processor)
staticsScope.processFunctionsByName(importedName) {
if (it.isStatic) processor(it.fir.buildImportedCopy(parentClassId).symbol)
else processor(it)
}
} else if (importedName.isSpecial || importedName.identifier.isNotEmpty()) {
for (symbol in provider.getTopLevelFunctionSymbols(import.packageFqName, importedName)) {
processor(symbol)
@@ -76,9 +81,18 @@ abstract class FirAbstractImportingScope(
for (import in imports) {
val importedName = name ?: import.importedName ?: continue
if (isExcluded(import, importedName)) continue
val staticsScope = import.resolvedParentClassId?.let(::getStaticsScope)
val parentClassId = import.resolvedParentClassId
val staticsScope = parentClassId?.let { getStaticsScope(it) }
if (staticsScope != null) {
staticsScope.processPropertiesByName(importedName, processor)
staticsScope.processPropertiesByName(importedName) {
if (it is FirPropertySymbol) {
if (it.isStatic) processor(it.fir.buildImportedCopy(parentClassId).symbol)
else processor(it)
} else {
processor(it)
}
}
} else if (importedName.isSpecial || importedName.identifier.isNotEmpty()) {
for (symbol in provider.getTopLevelPropertySymbols(import.packageFqName, importedName)) {
processor(symbol)
@@ -5,10 +5,7 @@
package org.jetbrains.kotlin.fir.scopes.impl
import org.jetbrains.kotlin.fir.declarations.FirCallableDeclaration
import org.jetbrains.kotlin.fir.declarations.FirDeclarationDataKey
import org.jetbrains.kotlin.fir.declarations.FirDeclarationDataRegistry
import org.jetbrains.kotlin.fir.declarations.FirDeclarationOrigin
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.declarations.builder.buildPropertyCopy
import org.jetbrains.kotlin.fir.declarations.builder.buildSimpleFunctionCopy
import org.jetbrains.kotlin.fir.scopes.FirContainingNamesAwareScope
@@ -26,13 +23,7 @@ class FirObjectImportedCallableScope(
) : FirContainingNamesAwareScope() {
override fun processFunctionsByName(name: Name, processor: (FirNamedFunctionSymbol) -> Unit) {
objectUseSiteScope.processFunctionsByName(name) wrapper@{ symbol ->
val function = symbol.fir
val syntheticFunction = buildSimpleFunctionCopy(function) {
origin = FirDeclarationOrigin.ImportedFromObjectOrStatic
this.symbol = FirNamedFunctionSymbol(CallableId(importedClassId, name))
}.apply {
importedFromObjectOrStaticData = ImportedFromObjectOrStaticData(importedClassId, function)
}
val syntheticFunction = symbol.fir.buildImportedCopy(importedClassId)
processor(syntheticFunction.symbol)
}
}
@@ -43,14 +34,7 @@ class FirObjectImportedCallableScope(
processor(symbol)
return@wrapper
}
val property = symbol.fir
val syntheticProperty = buildPropertyCopy(property) {
origin = FirDeclarationOrigin.ImportedFromObjectOrStatic
this.symbol = FirPropertySymbol(CallableId(importedClassId, name))
this.delegateFieldSymbol = null
}.apply {
importedFromObjectOrStaticData = ImportedFromObjectOrStaticData(importedClassId, property)
}
val syntheticProperty = symbol.fir.buildImportedCopy(importedClassId)
processor(syntheticProperty.symbol)
}
}
@@ -60,6 +44,25 @@ class FirObjectImportedCallableScope(
override fun getClassifierNames(): Set<Name> = emptySet()
}
internal fun FirSimpleFunction.buildImportedCopy(importedClassId: ClassId): FirSimpleFunction {
return buildSimpleFunctionCopy(this) {
origin = FirDeclarationOrigin.ImportedFromObjectOrStatic
this.symbol = FirNamedFunctionSymbol(CallableId(importedClassId, name))
}.apply {
importedFromObjectOrStaticData = ImportedFromObjectOrStaticData(importedClassId, this@buildImportedCopy)
}
}
internal fun FirProperty.buildImportedCopy(importedClassId: ClassId): FirProperty {
return buildPropertyCopy(this) {
origin = FirDeclarationOrigin.ImportedFromObjectOrStatic
this.symbol = FirPropertySymbol(CallableId(importedClassId, name))
this.delegateFieldSymbol = null
}.apply {
importedFromObjectOrStaticData = ImportedFromObjectOrStaticData(importedClassId, this@buildImportedCopy)
}
}
private object ImportedFromObjectOrStaticClassIdKey : FirDeclarationDataKey()
class ImportedFromObjectOrStaticData<D : FirCallableDeclaration>(
@@ -48,13 +48,11 @@ fun BodyResolveComponents.resolveRootPartOfQualifier(
for (scope in createCurrentScopeList()) {
scope.getSingleVisibleClassifier(session, this, name)?.let {
if (it is FirRegularClassSymbol) {
val isVisible = session.visibilityChecker.isVisible(
val isVisible = session.visibilityChecker.isClassLikeVisible(
it.fir,
session,
file,
containingDeclarations,
null,
false,
)
if (!isVisible) {
return@let
@@ -9,12 +9,11 @@ import org.jetbrains.kotlin.KtFakeSourceElementKind
import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.fakeElement
import org.jetbrains.kotlin.fir.*
import org.jetbrains.kotlin.fir.declarations.FirBackingField
import org.jetbrains.kotlin.fir.declarations.FirCallableDeclaration
import org.jetbrains.kotlin.fir.declarations.FirMemberDeclaration
import org.jetbrains.kotlin.fir.declarations.FirProperty
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.declarations.utils.getExplicitBackingField
import org.jetbrains.kotlin.fir.declarations.utils.isStatic
import org.jetbrains.kotlin.fir.declarations.utils.visibility
import org.jetbrains.kotlin.fir.expressions.FirResolvedQualifier
import org.jetbrains.kotlin.fir.expressions.FirSmartCastExpression
import org.jetbrains.kotlin.fir.expressions.FirVariableAssignment
import org.jetbrains.kotlin.fir.expressions.builder.buildSmartCastExpression
@@ -23,20 +22,27 @@ import org.jetbrains.kotlin.fir.types.coneType
import org.jetbrains.kotlin.fir.types.isNullableNothing
import org.jetbrains.kotlin.fir.types.makeConeTypeDefinitelyNotNullOrNotNull
import org.jetbrains.kotlin.fir.types.typeContext
import org.jetbrains.kotlin.utils.addToStdlib.runIf
fun FirVisibilityChecker.isVisible(
declaration: FirMemberDeclaration,
callInfo: CallInfo,
dispatchReceiverValue: ReceiverValue?
): Boolean =
isVisible(
): Boolean {
val staticQualifierForCallable = runIf(declaration is FirCallableDeclaration && declaration.isStatic) {
val explicitReceiver = callInfo.explicitReceiver ?: (dispatchReceiverValue as? ExpressionReceiverValue)?.explicitReceiver
(explicitReceiver as? FirResolvedQualifier)?.symbol?.fir as? FirRegularClass
}
return isVisible(
declaration,
callInfo.session,
callInfo.containingFile,
callInfo.containingDeclarations,
dispatchReceiverValue,
callInfo.callSite is FirVariableAssignment
staticQualifierClassForCallable = staticQualifierForCallable,
isCallToPropertySetter = callInfo.callSite is FirVariableAssignment
)
}
fun FirVisibilityChecker.isVisible(
declaration: FirMemberDeclaration,
@@ -132,12 +132,11 @@ abstract class FirDataFlowAnalyzer<FLOW : Flow>(
val symbol =
fullyExpandedType(components.session).lookupTag.toSymbol(components.session) ?: return false
val declaration = symbol.fir as? FirRegularClass ?: return true
visibilityChecker.isVisible(
visibilityChecker.isClassLikeVisible(
declaration,
components.session,
components.context.file,
components.context.containers,
dispatchReceiver = null
)
}
is ConeTypeParameterType -> true
@@ -6,6 +6,8 @@ package foo;
class Base {
protected static void foo() {}
protected void bar() {}
public static void baz() {}
}
// FILE: foo/Derived.java
@@ -24,3 +26,15 @@ class Impl : Derived() {
bar()
}
}
fun test() {
Derived.baz()
}
// FILE: withImport.kt
import foo.Derived.baz
fun test() {
baz()
}
@@ -1,6 +1,9 @@
package
public fun test(): kotlin.Unit
package bar {
public fun test(): kotlin.Unit
public final class Impl : foo.Derived {
public constructor Impl()
@@ -22,6 +25,7 @@ package foo {
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
// Static members
public open fun baz(): kotlin.Unit
protected/*protected static*/ open fun foo(): kotlin.Unit
}
@@ -33,6 +37,7 @@ package foo {
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
// Static members
public open override /*1*/ /*fake_override*/ fun baz(): kotlin.Unit
protected/*protected static*/ open override /*1*/ /*fake_override*/ fun foo(): kotlin.Unit
}
}